All Projects → TurpIF → lambda-string

TurpIF / lambda-string

Licence: MIT License
Lambda-string (LS) is a helping java agent that inject configurable toString method into lambdas with some useful meta-information.

Programming Languages

java
68154 projects - #9 most used programming language
shell
77523 projects

Projects that are alternatives of or similar to lambda-string

Inspectit Ocelot
inspectIT Ocelot - Java agent for collecting application performance, tracing and behavior data
Stars: ✭ 135 (+297.06%)
Mutual labels:  agent, jvm
Bistoury
Bistoury是去哪儿网的java应用生产问题诊断工具,提供了一站式的问题诊断方案
Stars: ✭ 3,198 (+9305.88%)
Mutual labels:  agent, jvm
github-task-manager
receive github hook, notify agent, receive task results, notify github
Stars: ✭ 13 (-61.76%)
Mutual labels:  agent, lambda
Arthas
Alibaba Java Diagnostic Tool Arthas/Alibaba Java诊断利器Arthas
Stars: ✭ 27,984 (+82205.88%)
Mutual labels:  agent, jvm
metrics-agent
JVM agent based metrics with Prometheus and Dropwizard support (Java, Scala, Clojure, Kotlin, etc)
Stars: ✭ 25 (-26.47%)
Mutual labels:  agent, jvm
mapneat
MapNeat is a JVM library written in Kotlin that provides an easy to use DSL (Domain Specific Language) for transforming JSON to JSON, XML to JSON, POJO to JSON in a declarative way.
Stars: ✭ 45 (+32.35%)
Mutual labels:  jvm
relearn
A Reinforcement Learning Library for C++11/14
Stars: ✭ 22 (-35.29%)
Mutual labels:  agent
eXperDB-Management
eXperDB-Management is a integrated management tool for PostgreSQL(for efficient operation and management).
Stars: ✭ 38 (+11.76%)
Mutual labels:  agent
spring-boot-lambda
No description or website provided.
Stars: ✭ 44 (+29.41%)
Mutual labels:  lambda
aws-pipeline
Build a CI/CD for Microservices and Serverless Functions in AWS ☁️
Stars: ✭ 32 (-5.88%)
Mutual labels:  lambda
zappa-blog
A blog about Zappa, powered by Zappa. Zappa zappa zappa. Zappa.
Stars: ✭ 17 (-50%)
Mutual labels:  lambda
JNotes
Java 工程师必备的技术知识点,全力打造Java 程序员的技能体系知识库;主要体现在 Java 基础、算法、网络、后端框架、数据库、操作系统等方面知识整理。对于Java 初学者升中高级、以及Java后端开发人员的的面试者都有非常显著的帮助。个人博客:www.husycode.cn
Stars: ✭ 33 (-2.94%)
Mutual labels:  jvm
serverless-plugin-lambda-dead-letter
serverless plugin that can configure a lambda with a dead letter queue or topic
Stars: ✭ 42 (+23.53%)
Mutual labels:  lambda
amqp-delegate
A simple, but performant, remote worker system that uses AMQP to coordinate jobs.
Stars: ✭ 22 (-35.29%)
Mutual labels:  agent
netlicensing.io
Labs64 NetLicensing - Innovative License Management Solution
Stars: ✭ 13 (-61.76%)
Mutual labels:  agent
play-scala-secure-session-example
An example Play application showing encrypted session management
Stars: ✭ 54 (+58.82%)
Mutual labels:  jvm
extract-css
Extract all CSS from a webpage, packaged as a Now V2 Lambda
Stars: ✭ 23 (-32.35%)
Mutual labels:  lambda
s3-lambda-transcribe-audio-to-text-s3
Transcribe your audio to text with this serverless component
Stars: ✭ 84 (+147.06%)
Mutual labels:  lambda
Apricot
Desktop Agent for Windows
Stars: ✭ 39 (+14.71%)
Mutual labels:  agent
play-scala-anorm-example
Example Play Database Application using Anorm
Stars: ✭ 41 (+20.59%)
Mutual labels:  jvm

lambda-string build status coverage report code quality

Lambda-string (LS) is a helping java agent that injects configurable toString method into lambdas with some useful meta-information.

LS comes with a default toString strategy that print the origin of the lambdas. This feature lets you easily track their origin while debugging as shown below :

With and without the agent

Usage

The most recent release is LS 0.2.

To activate the LS agent in general, please use the following:

To activate the LS agent using remote debugger, please use the following:

# Download JAR
wget -O /tmp/lambda-string-0.2.jar "https://gitlab.com/TurpIF/lambda-string/-/jobs/artifacts/v0.2/raw/target/lambda-string-0.2.jar?job=package-jdk8"

# Start debug server
cd /your/project
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=5005 -javaagent:/tmp/lambda-string-0.2.jar my.dummy.Main

# Attach a debugger client with JDB or your preferred IDE

To activate the LS agent using IntelliJ, please use the following:

  • Download the lambda-string-0.2.jar
  • Add -javaagent:/path/to/lambda-string-0.2.jar in the "VM options" of your debugging configuration

Intellij hint

To activate the LS agent with custom toString strategy, please use the following:

  • Download the lambda-string-0.2.jar
  • Add -javaagent:/path/to/lambda-string-0.2.jar=my.custom.ToStringStrategy in your java options

Why

This question is legitimate because a lambda should be restrained in a small scope. So, reading code using lambda should be simple and direct. Although, projects may grow quickly as their technical debt. This agent may help you in that case : when you lose the control of your lambda, and you can't tell which one is it.

package com.dummy;

public class Main {

  @FunctionalInterface
  interface Foo {
    void foo();
  }

  public static Foo createFoo(int param) {
    switch (param) {
      case 1:
        return () -> { /* do 1 */ };
      case 2:
        return () -> { /* do 2 */ };
    /* ... */
      default:
      return () -> { /* do default */ };
    }
  }

  public static void main(String[] args) {
    Integer param = Integer.valueOf(args[0]);
    Foo foo = createFoo(param);
    /* We have a foo, but which one ? The injected toString will tell you */
  }

}

In the above sample, the lambda is chosen from a runtime value. While debugging, if you put a breakpoint after the generation of the lambda, you can't tell which lambda is returned by the method. By activating the LS agent, the lambda origin is available through its toString evaluation.

Benchmark

This agent should be used during a debugging session with human interaction, so a little performance overhead is still acceptable as long as it is not perceptible by a human. Although, here is some benchmarks to give you some ideas of the potential impacts :

To reduce the impacts, a particular attention is done when transforming the lambda runtime representations. Also, the majority of the computation is done when toString is effectively called. This avoids the performance cost until a true human interaction.

The benchmarks are done with JMH on a Gitlab shared agent. So the absolute metrics may be wrong, but the important part is the relative comparison with and without the agent.

Creation of lambdas

The LambdaCallSiteGenerationComparisonBenchmark benchmark compares the time the JRE spends generating a class instance (and its constant call site) from a lambda. This is done only once per lambda. Currently, on the HostSpot JVM 8, the JRE takes roughly 50ns to generate a lambda call site without the agent and 100ns with. So yes, there is an overhead, but your JRE can still generate 10 000 000 lambdas per seconds (and if you have so many lambdas in your code base, I guess that one second is not that much compared to the others kinds of issues you may have).

Cost of strategy call

The OriginalToStringInjectionComparisonBenchmark benchmark compares the time the JRE spends returning the Object#toString() of a lambda. Without an agent, the original toString is simply called. With the agent, a LambdaToStringStrategy is installed to reproduce the orignal. Roughly, both versions take the same time. So, there isn't any impact when injecting a strategy that reproduces the same output than a real toString.

Cost of the debugging strategy

The DefaultToStringStrategyComparisonBenchmark benchmark compares the time spent by the JRE to return the original toString compared to returning a useful debugging toString as shown above. The debugging strategy exceeds few milliseconds. Although, this stays imperceptible for a human

Customizing injected toString

It is possible to give a custom toString strategy to the agent. For this, you should first create a new implementation of the LambdaToStringStrategy interface.

Then the agent setup should give the custom strategy class as below :

java -javaagent:./lambda-string-0.2.jar=my.dummy.MyToStringStrategy my.dummy.Main

Here is a sample of custom strategy, returning a constant toString :

public final class MyToStringStrategy implements LambdaToStringStrategy {
    @Override
    public String createToString(Object lambda, LambdaMetaInfo metaInfo) {
        return "Hello world";
    }
}

Contributing

When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.

Prerequisites

Installing a development environment needs few requirements:

Installation

git clone https://gitlab.com/TurpIF/lambda-string lambda-string
cd lambda-string
mvn verify

Testing the agent on different JRE is eased with the GitLab Runner and Docker. Also, few scripts are available to simulate the gitlab CI pipeline through a shared directory amongst the dockers. Available testing JRE tasks are those matching the test-jre* pattern in the GitLab CI file.

git clone https://gitlab.com/TurpIF/lambda-string lambda-string
cd lambda-string

# GitLab Runner does not allow running pipeline with shared artifact, so the build-jre8 task should be called
# once before running any testing task.
# Task outputs are shared in the /tmp/output directory of the host. 

# Build the agent
./src/test/shell/build-jdk8.sh

# Test the agent with JRE 9
./src/test/shell/test-jre.sh test-jre9

# Test with a debugging server listening the port 9000
./src/test/shell/test-jre.sh test-jre10 9000

Calling those scripts may fail if your use is not allowed to use the docker socket. You should either make this available to your user (see docker docs), or run the script with sudo.

Running the benchmarks locally is equivalent to execute the tests. Available benchmarking JRE tasks are those matching the benchmark-jre* pattern in the GitLab CI file.

git clone https://gitlab.com/TurpIF/lambda-string lambda-string
cd lambda-string

# Build the agent and the benchmark JAR
./src/test/shell/build-jdk8.sh
./src/test/shell/test-jre.sh build-benchmark

# Benchmark the agent with JRE 10
./src/test/shell/test-jre.sh benchmark-jre10

Known issues

Lambdas loaded during bootstrap are not supported (as Function.identity()):

This is because, by default, agents are loaded by the system class loader after the bootstrap one. So, already visited lambda have already an abstract class representation. Also, this representation is not retransformable and then not injectable.

Attaching the agent during a JVM runtime is not well supported:

It is possible to attach an agent to a running JVM. But LS does not support injecting toString in lambdas that are already loaded by the JVM.

Supported JVMs

Here is the list of the tested and working JREs:

  • HotSpot JVM 1.8
  • HotSpot JVM 9
  • HotSpot JVM 10
  • IBM J9 VM (JRE 8)
Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].