تعد مجموعة أدوات Java Observability Toolkit (JOT) بمثابة منصة لجعل أي تطبيق Java قابلاً للملاحظة دون كتابة أي تعليمات برمجية أو حتى إعادة الترجمة. تتكون المنصة من...
يمكنك إنشاء JOTs بسرعة وسهولة دون أي تعليمات برمجية. يمكن لـ JOTs أن تجعل أي شيء تقريبًا في تطبيق Java قيد التشغيل قابلاً للملاحظة. فيما يلي بعض الأمثلة لما قد تستخدمه من أجله... ولكن الحد الوحيد هو إبداعك.
أنت عالق في استكشاف مشكلة الإنتاج وإصلاحها وليس لديك سجلات كافية أو القدرة على تصحيح الأخطاء. باستخدام قاعدة JOT البسيطة، يمكنك الحصول على البيانات التي تحتاجها بسرعة وسهولة.
أنت تريد مراقبة شيء لا يمكن الوصول إليه إلا بعمق داخل التطبيق وليس لديك طريقة لعرضه على أدواتك.
تريد منع إساءة استخدام الأساليب القوية من قبل المهاجمين، ولكنها موجودة في مكتبات لا يمكنك التحكم فيها.
هدف JOTs هو توفير أقصى قدر من قوة الأجهزة دون المساس بالبساطة.
أخبرنا بالأشياء الرائعة التي تفعلها مع JOT! وفكر في المساهمة بهم مرة أخرى في المشروع حتى يتمكن الآخرون من المشاركة في روعتك. أسهل طريقة للمساهمة هي إنشاء طلب سحب. إذا كنت تشارك JOT، فأضفه إلى دليل "المساهمة" الخاص بالمشاريع... ويرجى تضمين تعليق يوضح بالتفصيل الغرض من استخدامه.
حدد أجهزة الاستشعار والتقارير الخاصة بك في 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"
كل ما عليك فعله هو إضافة JOT إلى JVM
ثم يمكنك فقط استخدام التطبيق الخاص بك بشكل طبيعي والسماح لـ 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.
إذا كنت تريد استخدام JOTs متعددة في نفس الوقت، فيمكنك إما وضعها جميعًا في ملف .jot كبير واحد، أو يمكنك وضع ملفات .jot متعددة في دليل واستخدام "-javaagent:jot.jar=directory"
وأخيرًا، يمكن أن تحتوي كل JOT على "لقطات" متعددة. الالتقاط هو وسيلة لتحديد البيانات التي تريد جمعها من الطرق التي حددتها في JOT. عمليات الالتقاط البسيطة هي أشياء مثل: #P0 - المعلمة الأولى #P1 - المعلمة الثانية #ARGS - جميع المعلمات المتسلسلة في سلسلة #OBJ - الكائن الذي يتم استدعاء الطريقة عليه #RET - الإرجاع من الطريقة
الالتقاطات هي في الواقع تعبيرات لغة Spring Expression Language (SpEL)، لذا يمكنك استدعاء الأساليب على تلك الكائنات الأساسية ومقارنة الأشياء وإجراء العمليات. وهذا يساعدك على ملاحظة ما تريده بالضبط. انظر أدناه للحصول على كافة تفاصيل كتابة أجهزة الاستشعار الخاصة بك.
يستخدم JOT FluentLogger الذي يأخذ التكوين من java.util.logging
ويمكن تهيئته بواسطة JVM باستخدام -Djava.util.logging.config.file
سيقوم نموذج التكوين هذا بتسجيل 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"
يجب أن يكون الأمر بسيطًا مثل استنساخ هذا الريبو والبناء باستخدام المخضرم
$ 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"