JOT(Java Observability Toolkit)는 코드를 작성하거나 재컴파일하지 않고도 모든 Java 애플리케이션을 관찰 가능하게 만드는 플랫폼입니다. 플랫폼은 다음과 같이 구성됩니다.
별도의 코딩 없이 쉽고 빠르게 JOT를 생성할 수 있습니다. JOT는 실행 중인 Java 애플리케이션의 모든 것을 관찰 가능하게 만들 수 있습니다. 다음은 귀하가 사용할 수 있는 몇 가지 예입니다... 그러나 유일한 한계는 귀하의 창의성입니다.
프로덕션 문제를 해결하는 데 어려움을 겪고 있고 로그나 디버그 기능이 충분하지 않습니다. 간단한 JOT 규칙을 사용하면 필요한 데이터를 빠르고 쉽게 얻을 수 있습니다.
앱 내부에서만 액세스할 수 있는 항목을 모니터링하려고 하는데 이를 도구에 노출할 수 있는 방법이 없습니다.
공격자가 강력한 방법을 남용하는 것을 방지하고 싶지만 이러한 방법은 제어할 수 없는 라이브러리에 있습니다.
JOT의 목표는 단순성을 손상시키지 않으면서 최대의 계측 성능을 제공하는 것입니다.
당신이 JOT로 하는 멋진 일들을 알려주세요! 그리고 다른 사람들이 당신의 멋진 모습을 공유할 수 있도록 프로젝트에 다시 기여하는 것을 고려해 보세요. 기여하는 가장 쉬운 방법은 끌어오기 요청을 만드는 것입니다. JOT를 공유하는 경우 프로젝트의 "contrib" 디렉토리에 추가하고 용도를 자세히 설명하는 설명을 포함하세요.
센서와 보고서를 yaml로 정의하고 .jot 파일에 저장하세요. 센서는 캡처할 데이터를 정의하고 "보고"는 JOT에게 시간 경과에 따라 데이터를 추적하는 방법을 알려줍니다.
sensors:
- name: "get-ciphers"
description: "Identifies encryption ciphers"
methods:
- "javax.crypto.Cipher.getInstance"
captures:
- "#P0"
reports:
- name: "Encryption Usage"
type: "list"
cols: "get-ciphers"
기본적으로 JVM에 JOT를 추가하기만 하면 됩니다.
그런 다음 애플리케이션을 정상적으로 사용하고 JOT가 데이터를 수집하도록 하세요. JOT는 암호화가 사용되는 위치와 지정된 알고리즘을 정확하게 캡처하는 멋진 테이블을 만듭니다.
Encryption Algorithms get-ciphers
------------------------------------------------------------ ----------------------
com.acme.ticketbook.Ticket.encrypt(Ticket.java:125) DES
org.apache.jsp.accessA_jsp._jspService(accessA_jsp.java:212) AES
org.apache.jsp.accessA_jsp._jspService(accessA_jsp.java:213) PBEWithMD5AndTripleDES
org.apache.jsp.accessB_jsp._jspService(accessB_jsp.java:212) DES
org.apache.jsp.accessC_jsp._jspService(accessC_jsp.java:212) DES/CBC/PKCS5Padding
JAVA_TOOL_OPTIONS 환경 변수를 사용하는 것이 유용할 수 있습니다. "export JAVA_TOOL_OPTIONS="-javaagent:jot.jar=ciphers.jot"와 같습니다. 그러면 Java가 결국 어떻게 시작되든 JOT를 사용하게 됩니다.
동시에 여러 개의 JOT를 사용하려면 하나의 큰 .jot 파일에 모두 넣거나 여러 .jot 파일을 디렉터리에 넣고 "-javaagent:jot.jar=directory"를 사용할 수 있습니다.
마지막으로 모든 JOT에는 여러 개의 "캡처"가 있을 수 있습니다. 캡처는 JOT에 지정한 방법에서 수집하려는 데이터를 지정하는 방법입니다. 간단한 캡처는 다음과 같습니다: #P0 - 첫 번째 매개변수 #P1 - 두 번째 매개변수 #ARGS - 문자열로 연결된 모든 매개변수 #OBJ - 메소드가 호출되는 객체 #RET - 메소드의 반환
캡처는 실제로 SpEL(Spring Expression Language) 표현식이므로 기본 개체에 대한 메서드를 호출하고 항목을 비교하고 작업을 수행할 수 있습니다. 이는 원하는 것을 정확히 관찰하는 데 도움이 됩니다. 자신만의 센서를 작성하는 방법에 대한 자세한 내용은 아래를 참조하세요.
JOT는 java.util.logging
에서 구성을 가져오고 -Djava.util.logging.config.file
사용하여 JVM에서 구성할 수 있는 FluentLogger를 사용합니다.
이 샘플 구성은 JOT를 stdout 및 /tmp/jot.log에 기록합니다.
handlers = java.util.logging.ConsoleHandler, java.util.logging.FileHandler
java.util.logging.ConsoleHandler.level = ALL
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format = %1$tF %1$tT %4$-7s [%2$s] - %5$s %n
java.util.logging.FileHandler.level=ALL
java.util.logging.FileHandler.pattern=/tmp/jot.log
java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter
java.util.logging.FileHandler.append=true
사용:
java -javaagent:jot.jar=ciphers.jot -Djava.util.logging.config.file=/root/jul.properties
센서는 수집하려는 데이터를 정의하는 방법입니다. 센서를 사용하여 애플리케이션 내에서 제한된 작업을 수행할 수도 있습니다.
# The name of this sensor, which can be referenced by reports
- name: "get-ciphers"
# Use this to describe what this sensor does. Try to provide enough
# detail so that anyone would understand what it's about.
description: "What does sensor do?"
# A list of methods to gather data from. To avoid potential performance issues,
# avoid putting sensors in methods that are extremely frequently used,
# like StringBuffer.append() or File.<init>.
methods:
- "a.b.c.Class.method"
- "d.e.f.Class.method"
# Scopes allow you to limit when a sensor will fire.
# A sensor will fire if it is invoked while "inside" one of the scopes. That is,
# when any of these methods is on the stack.
# You can define negative scopes using !scope, so that this sensor will only fire outside the scope
# For static methods you need to prefix the method with "static"
scopes:
- "a.b.c.Class.method" # matches only if inside method
- "!a.b.c.Class.method" # matches only if NOT inside method
- "static a.b.c.Class.method" # matches if inside static method
# Excludes allow you to prevent data from being gathered from any
# classes that starts with any of these patterns or are "isAssignableFrom" these classes
# FIXME: currently you must put .all after each classname
excludes:
- "javax.el.MapELResolver.all"
- "org.foo.package.all"
# Captures are the workhorse of JOT and are written in Spring Expression Language (SpEL)
# You may reference data from the method currently running.
# Options are OBJ, P1..P10, ARGS, RET, STACK. These objects are whatever type they happen
# to be, and you can invoke any existing methods on those objects. Note that STACK is a StackFrame[]
# See https://blog.abelotech.com/posts/useful-things-spring-expression-language-spel/
captures:
- "#RET?.toUpperCase()" # call toUpperCase if #RET is not null (note ?. operator)
- """+#P0+":"+#RET" # for methods that take a name and return a value
- "#OBJ.getCanonicalPath() + " " + #OBJ.exists() ? [EXISTS] : [DOES NOT EXIST]" # use ternary operator
- """+#P0+":"+(#RET ? "Y" : "N")" # for methods that return boolean
# Matchers allow you to filter the data that was captured with a set of regular expressions.
# If there are no matchers then all captures will report data.
# Positive matchers only fire if the data matches the pattern. You'll get a result if any positive matchers match.
# Negative matchers (starting with !) only fire if the data does not match the pattern. You'll get a result if no negative matchers match.
# If you mix positive and negative, you'll get a result if any positive captures match and no negative matchers match.
matchers:
- "^\w*$" # matches anything with word characters start to finish
- "!^\[foo" # matches anything that doesn't start with foo
- "!null" # hide empty results from output
# Exceptions are a way to change the behavior of an application.
# If the sensor fires (capture occurs and matchers fire) then JOT will
# throw a SensorException.
# The message should be appropriate for end user, JOT will log all the relevant details.
# Note that generally you don't want to use #RET in your capture if you're throwing an exception,
# because it will throw at the end of the method, which is probably too late.
exception: "Message"
# Debug mode will generate extra logging for this rule only
debug: "false"
보고서를 사용하면 JOT가 시간이 지남에 따라 데이터를 수집하는 방법과 형식을 지정하는 방법을 정의할 수 있습니다.
# Title of this report that will be displayed above the results
- name: "example"
# Type of reports include
# 1. list
# ROWS: caller method
# COLS: one column named after the sensor defined in "cols"
# DATA: values from the sensor named in "cols"
# 2. compare
# ROWS:
# COLS: uses the "cols" sensor values as column headers
# DATA: values from the sensor named in "cols"
# 3. table
# ROWS:
# COLS: uses rule names for cols[0-n] as column headers - parses data values
# DATA: values from the sensor named in "cols"
# 4. series - table but each row starts with a timestamp (currently includes callers col too)
# ROWS:
# COLS: uses rule names for cols[0-n] as column headers - parses data values
# DATA: values from the sensor named in "cols"
type: "table"
# Rows indicates a sensor to be used to populate row headers
rows: "get-routes"
# Cols indicates a sensor (or list of sensors) to be used to populate column headers
cols: "get-users"
# Data indicates how the content of data cells should be populated. Can be a fixed string or a rule name.
data: "X"
이 저장소를 복제하고 Maven으로 구축하는 것만큼 간단해야 합니다.
$ git clone https://github.com/planetlevel/jot.git
$ cd jot
$ mvn install
그런 다음 대상 디렉터리에서 jot-xxjar를 사용할 수 있습니다.
기여를 환영합니다. JOT를 더 좋게 만들고 싶다면 버그 추적기를 참조하여 작업할 문제를 찾으세요.
- Solve problem of sensors inside JOT scope
1) don't instrument JOT classes -- anything using shading
2) use global scope to check anywhere you're inside a sensor call
- Create separate JOT log file instead of using java.util.logging
- New rules
1) which routes are non-idempotent?
- Sensors
# future features - maybe think about reporting?
# enabled: "false"
# sample: "1000" # report every 1000 times? time frequency?
# counter: "?" # report 10 mins?
# scope: include a capture and regex to say whether to start scope (if service.P0.getParameter=foobar)
# exec: run this code. before? after? during?
- Reports
# possible additions to cols -- caller, stack[n], trace#
- Query Language
# investigate using query language instead of yaml jots.
# Perhaps two types of "queries" -- one to create sensors, another to pull reports.
# SELECT #P0.toUpperCase()
FROM java.lang.Runtime.getRuntime.exec
WITHIN javax.servlet.Servlet.service
WHERE pattern
# SELECT [capture, capture]
FROM [method, method]
EXCLUDE [class, class]
WITHIN [scope, scope]
WHERE [pattern, pattern]
THROWS [msg]
# SELECT #P0 FROM javax.crypto.Cipher.getInstance
# SELECT #P0 FROM javax.crypto.Cipher.getInstance
WHERE "DES|DESEDE"
THROWS "Weak encryption algorithm detected"