Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FEATURE] Debugging invalid references. #570

Closed
DaanVanYperen opened this issue May 11, 2019 · 57 comments
Closed

[FEATURE] Debugging invalid references. #570

DaanVanYperen opened this issue May 11, 2019 · 57 comments
Assignees
Milestone

Comments

@DaanVanYperen
Copy link
Collaborator

DaanVanYperen commented May 11, 2019

as a framework user
I want to log when and where entities are created or destroyed.
So that I can debug reference issues.

Criteria (edit after discussion)

  • Debug plugin
    • Ability to detect illegal access to components and entities.
    • Ability to report the cause (for example, delete issued in class@linenumber).
    • Ability to log all lifecycle events (optional).
    • Expose all debug information to ECS (via components).
    • Lifecycle naming of entities for easy tracking.
    • Extend/replace logging and naming.
    • Plug and play.
  • Lifecycle listener plugin.
    • Intended to augment editors and debuggers.
    • Can be disabled. No performance impact when disabled.
    • Hook into lifecycle events for Entities and Components.
    • Hook into lifecycle events for World (?)
    • Plug and play.

Code example

To log all calls coming from net.mostlyoriginal package.

WorldConfigurationBuilder.with(DebugPlugin.thatLogsErrorsIn("net.mostlyoriginal"))

log output (Proof of concept)

NotableNautilus(1) CREATE @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:85)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)
NotableNautilus(1) DELETE @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:90)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)
*********************
NotableNautilus(1) ERROR_ATTEMPT_TO_DELETE_DELETED_ENTITY @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:91)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)
Cause (Already deleted at):
NotableNautilus(1) DELETE @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:90)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)
*********************

Background

While attempting to refactor a Jam game into a more best practices example for ECS I'm running into a lot of bugs related to expired id references, even with the help of @EntityId.

@junkdog
Copy link
Owner

junkdog commented May 12, 2019

Do we really need to extend the world? A custom SystemInvocationStrategy exposes initialize, setSystems but probably missing hooks for updateEntityStates for it to be convenient.

I don't mind including a logging facade. I find logback to be pretty good. Could use proguard to strip all logging-related code from non-debug artifacts.

An EntitySubListener (or system) for Aspect.all() could supply entities with a secondary id/counter in inserted(Entities).

@DaanVanYperen
Copy link
Collaborator Author

DaanVanYperen commented May 12, 2019

I agree with you, ideally i'd be able to use the Plugin API and not touch world directly. Would be easier to use for the end user and solve some order of operation issues as well. Think it can be done if you don't mind some small changes to WorldConfiguration, specifically adding the ability to supply an extended batchProcessor and entityManager.

Got a PoC running with DebugWorld. Overriding world.deleteto get the stacktrace at the moment user calls for deletion, which is handled by batchProcessor which isn't exposed in WorldConfiguration (yet). For creation calls a custom entitymanager is supplied.

Slap DebugComponent on the entity at creation so user can use it for their own debugging systems, and track it separately so we can always access it even if the world lifecycle hasn't updated.

https://gist.github.com/DaanVanYperen/e2ab0143f2b92e49d064c913c3fc6a02

Don't know about logback for this use case, just got a very basic callback that doesn't assume anything. Proguard for a debug artifact with broader debugging might be coolies?

    public interface DebugLogStrategy {
        void log(String s);

        void log(MutationStacktrace site);
    }

Works pretty great so far, figured out my bug in no time. Coolest thing is the gfycat name gen ;)

AdmiredFallowdeer(0) CREATE @ net.mostlyoriginal.api.SingletonPlugin$SingletonFieldResolver.initialize(SingletonPlugin.java:40)
RustyTinamou(1) CREATE @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:85)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)

@junkdog
Copy link
Owner

junkdog commented May 12, 2019

Going to bed, already late, (belated hi!), so forgive the brevity - but this was cool, so I had to reply.

Think it can be done if you don't mind some small changes to WorldConfiguration, specifically adding the ability to supply an extended batchProcessor and entityManager.

Hmm, couldn't we provide similar functionality by opening up said classes with the appropriate optional callbacks? It's easier to iterate on the internal design if we can negate the need to extend the classes in the first place, instead providing custom logic via listeners.

Got a PoC running with DebugWorld. Overriding world.deleteto get the stacktrace at the moment user calls for deletion, which is handled by batchProcessor which isn't exposed in WorldConfiguration (yet). For creation calls a custom entitymanager is supplied.

Hmm, maybe an interface Entity.OnIssuedDelete(-Listener) - doesn't have to go into the Entity class, but could - invoked when World.delete(int) is called? Could do a similar one for Entity.OnIssuedCreate. This type of callbacks are useful for editors too.

    public interface DebugLogStrategy {
        void log(String s);

        void log(MutationStacktrace site);
    }

Any chance of doing it as a SAM type (single abstract method)? With android 8 bytecode now being kosher on android and kotlins lambdas play nice with SAM types - it's pretty neat means of omitting boilerplate. I think a default implementation for void log(MutationStacktrace) would suffice in making it qualify as a SAM type.

or wait... are we running into GWT limitations?

Works pretty great so far, figured out my bug in no time. Coolest thing is the gfycat name gen ;)

Really like the idea and output! I would personally prefer shorter names + maybe custom logic (say, entities name prefix from team/enemy type etc), so better have a gfycat name factory interface ;)

hrrm.. scope.

@DaanVanYperen
Copy link
Collaborator Author

appropriate optional callbacks?

That would be a lot cleaner, originally went for 'no performance impact for production' as a criteria which causes some of these hoops. If you don't see an issue with it, one null check per call isn't /too/ expensive.

SAM seems fine solution. Name from component is a lifecycle thing, at the moment of creation the composition isn't there yet. GWT we can just test.

@DaanVanYperen
Copy link
Collaborator Author

DaanVanYperen commented May 13, 2019

@junkdog See several ways to do this.

  • mySystem implement EntityLifecycleListener, scanner gathers impls, simple null check at call sites.
  • WorldConfiguration.register(EntityLifecycleListener), allow one, or multiple.

Kinda charmed of the (edit)FIRST one.

Any other callsites you need for editors? ->

/**
 * Listener for events in the entity lifecycle.
 *
 * Use this for debugging or cases where you need to decorate every entity.
 *
 * @author junkdog
 * @author Daan van Yperen
 */
@UnstableApi
public interface EntityLifecycleListener {

    /**
     * Intercept deletion issued.
     *
     * Triggers on {@code deleteFromWorld} invocations, just before the entity
     * is scheduled for deletion. Accessing components is still allowed.
     *
     * Entity deletion is finalized at a later moment in the engine lifecycle.
     *
     * @param entityId
     */
    void onEntityDeleteIssued(int entityId);

    /**
     * Intercept entity post creation.
     *
     * @param entityId Id of created Entity.
     */
    void onEntityCreated(int entityId);

    /**
     * Intercept entity pre get.
     *
     * Triggers when {@code EntityManager.getEntity} is called, just before
     * actually resolving the entity. The entity is not guaranteed to exist.
     *
     * @param entityId id of the entity to get.
     */
    void onEntityGet(int entityId);
}

@junkdog
Copy link
Owner

junkdog commented May 13, 2019

That would be a lot cleaner, originally went for 'no performance impact for production' as a criteria which causes some of these hoops.

It should be fine; if it's a hit, we can always ASM it away at a later date (kotlin go very well together with ASM's tree API).

  • mySystem implement EntityLifecycleListener, scanner gathers impls, simple null check at call sites.

EntityManager.register(EntityLifecycleListener) - during EntityManager.initialize() auto-registers all systems implementing said interface. Need an unregister(EntityLifecycleListener) too. Too avoid confusing use-cases, allow for any number of listeners.

public interface EntityLifecycleListener

Not sure about onEntityGet() - what's the use-case for it? Otherwise looking good.

DaanVanYperen added a commit that referenced this issue May 13, 2019
@DaanVanYperen
Copy link
Collaborator Author

Not sure about onEntityGet() - what the use-case for it?

This would allow the debug plugin to report the delete-issued stacktrace when illegally accessing a deleted entity.

@DaanVanYperen
Copy link
Collaborator Author

EntityManager.register(EntityLifecycleListener) - during EntityManager.initialize() auto-registers all systems implementing said interface. Need an unregister(EntityLifecycleListener) too. Too avoid confusing use-cases, allow for any number of listeners.

Ah makes sense, the PR is static, I'll make it dynamic.

@junkdog
Copy link
Owner

junkdog commented May 13, 2019

onEntityGet() - it feels considerably more heavy than the others and I'm not convinced it captures all the use-cases.

Can we get rid of bit but still find a way forward? How about catching it in InvocationStrategy + maybe a default exception handler (although, I guess that's project-specific)? Still need to find out how to propagate the requested/deleted entity though.

@DaanVanYperen
Copy link
Collaborator Author

NotableNautilus(1) CREATE @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:85)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)
NotableNautilus(1) DELETE @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:90)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)
*********************
NotableNautilus(1) ERROR_ATTEMPT_TO_DELETE_DELETED_ENTITY @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:91)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)
Cause (Already deleted at):
NotableNautilus(1) DELETE @ net.mostlyoriginal.game.system.map.TiledMapManager.createLayerEntity(TiledMapManager.java:90)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.load(TiledMapManager.java:73)
       .. net.mostlyoriginal.game.system.map.TiledMapManager.initialize(TiledMapManager.java:62)
*********************

@junkdog
Copy link
Owner

junkdog commented May 13, 2019

Really cool!

@DaanVanYperen
Copy link
Collaborator Author

onEntityGet() - it feels considerably more heavy than the others and I'm not convinced it captures all the use-cases.

Lets just remove that then. It's a little less convenient but users can still use the log to determine the point of deletion with a quick search.

Is there a good usecase for the runtime removable listener feature? Could save a bit of time not making that.

@junkdog
Copy link
Owner

junkdog commented May 13, 2019

Lets just remove that then. It's a little less convenient but users can still use the log to determine the point of deletion with a quick search.

NoSuchEntityException?

Is there a good usecase for the runtime removable listener feature? Could save a bit of time not making that.

Not a good enough one - skip it. Everything tends to have their lifetimes aligned with the world's anyway.

@DaanVanYperen
Copy link
Collaborator Author

NoSuchEntityException

Is try/catch free if not triggered? That would require us to WorldManager.getEntity rethrow as NoSuchEntityException?

If it is free, could we just try { } catch ( E e ) { listeners.onGetInvalidEntity(id) }?

@junkdog
Copy link
Owner

junkdog commented May 13, 2019

Yeah, it should probably be benchmark, but I think we'd be fine

@DaanVanYperen
Copy link
Collaborator Author

Have you joined the libgdx discord yet? there's a (text) channel there with a lot of active users, people ask for updated benchmarks frequently.

@DaanVanYperen
Copy link
Collaborator Author

DaanVanYperen commented May 13, 2019

Crap, it is a bag, so when we get what was once a valid id it will probably not throw a ArrayIndexOutOfBoundsException. So we would have to do a null check in addition to the exception handler.

   protected Entity getEntity(int entityId) {
        try {
            final Entity entity = entities.get(entityId);
            if (entity == null)
                throw new EntityNotFoundException("Entity with id " + entityId + " does not exist. Deleted?");
            return entity;
        } catch (ArrayIndexOutOfBoundsException | EntityNotFoundException e) {
            if (entityLifecycleListener != null) {
                // callback on failed get.
                entityLifecycleListener.onEntityNotFoundException(entityId);
            }
            throw e;
        }
    }

@DaanVanYperen
Copy link
Collaborator Author

PoC plugin can be reviewed at DaanVanYperen/artemis-odb-contrib@a3eec84

Can report errors OR everything. Just needs a way to supply user chosen (shorter) entity names.

WorldConfigurationBuilder.with(DebugPlugin.thatLogsErrorsIn("net.mostlyoriginal"))
WorldConfigurationBuilder.with(DebugPlugin.thatLogsEverythingIn("net.mostlyoriginal"))

Accessor detection isn't great yet, since ComponentMapper doesn't even hit EntityManager if you work with ints, and bums out with a ArrayIndexOutOfBoundsException. perhaps wrapping strategy would work better after all.

@junkdog
Copy link
Owner

junkdog commented May 14, 2019

Crap, it is a bag, so when we get what was once a valid id it will probably not throw a ArrayIndexOutOfBoundsException. So we would have to do a null check in addition to the exception handlerr

If we can skip gwt compat for this part of the feature, I can throw together a classloader to record last accessed entity id. Apart from gwt, the caveat is that one needs to activate it before referencing the world class.

@junkdog
Copy link
Owner

junkdog commented May 14, 2019

So we would have to do a null check in addition to the exception handler.

It could be argued that it's valid to ask for an entity which doesn't exist. Would likely break someone's code.

@DaanVanYperen
Copy link
Collaborator Author

If we can skip gwt compat for this part of the feature, I can throw together a classloader to record last accessed entity id.

GWT compat is optional IMO, let users spin up desktop if they want to debug. That said, after lurking in the libgdx discord for a bit people already struggle with the build complexity of odb, especially when using the more exotic features. Is there some way to go vanilla without extra hoops?

It could be argued that it's valid to ask for an entity which doesn't exist. Would likely break someone's code.

I agree. The listener shouldn't alter behavior if we can avoid it. I'll revert the getEntity changes after work.

In the end the issues you'd want to catch with DebugPlugin would require some broader hooks anyway. (ComponentMapper for example). Perhaps extending classes (except World) would be a valid trade-off after all. If we jump to proxy classes or runtime class generation might as well just manually subclass and keep things easier to understand. None of that needs to end up in the odb repo, it's mostly debug plugin specific.

To make the PoC production ready plan to write some test cases for the DebugPlugin with all the ways users can shoot themselves in the foot, and try to cover all those. That should give us a better idea what it'll touch.

@DaanVanYperen
Copy link
Collaborator Author

Oh just noticed this on gitter: https://github.com/Namek/artemis-odb-entity-tracker/tree/develop
Poke @Namek

At work so haven't investigated where our needs overlap.

@DaanVanYperen
Copy link
Collaborator Author

Ok. I'll see towards some more clarity on the needed hooks for my use case. Should be able to produce a more concrete listener interface. Probably best to store the static reference for the singleton listener separate from the interface and keep it lean and mean.

AspectJ support runtime stuff? Haven't looked at that in forever.

@junkdog
Copy link
Owner

junkdog commented May 15, 2019

Never touched AspectJ - wasn't it hindered by a software patent?

So, for defining the bytecode-transplanting templates - this is how I envision they'd look/function:

// package is unimportant / not our concern
package mygame.artemis.hello;

import com.artemis.ComponentMapper;

// required annotation: select target class 
@Graft.Target(ComponentMapper.class)
// name can be anything, but generic signature must match
public class ComponentMapperTransplant<A> { 

    @Graft.Prepend // one could possibly also Graft.Append, Graft.Replace, Graft.Skip
    public A get(int entityId) throws ArrayIndexOutOfBoundsException {
        log(entityId, Type.MAPPER_GET, false);
        return get(entityId); // N.B. seemingly recursive call
    }

    // method signature must match target method
    @Graft.Prepend
    public A create(int entityId) {
        log(entityId, Type.MAPPER_CREATE, true); 
        return create(entityId);
    }

    // non-annotated methods copied to target class as-is (validation error if already exists)
    private static void log(int entityId, Type type, boolean generateStackTrace) {
        // this assumes that StaticDebugEventTrace is accessible
        // when writing these templates
        StaticDebugEventTrace.entityId = entityId;
        StaticDebugEventTrace.type = type;

        // maybe stacktrace or other loggable stuff
    }
}
  • the "recursive" call acts as a known marker in the ASM code (easy to intercept), but can conceptually be thought of as continuing with the original method
  • Transplant classes are annotated with Graft.*
  • Only @Graft.Target is strictly required
  • @Graft.Skip is useful to make compilation pass; e.g. @Graft.Skip World world;
  • fields can also be transplanted
  • can be expanded to more use-cases/classes without requiring changes to the underlying instrumentation code
  • In theory, this approach mitigates the need for the singleton altogether

Feedback welcome. It's a bit quirky perhaps, but it doesn't have a lot of moving parts from the user POV.

@junkdog
Copy link
Owner

junkdog commented May 15, 2019

This approach would also result in getting rid of almost all the old ASM code - most of the existing stuff can be expressed with *Transplants.

@DaanVanYperen
Copy link
Collaborator Author

The grafting API looks good. I suspect I'm not getting the limitations or how this circumvents singleton (isn't that what StaticDebugEventTrace would be?)

I'm splitting the debugger into a listener plugin and a debugger plugin, but that doesn't change the grafting API itself I guess. How flexible is this? Would this be legal?

@Graft.Target(ComponentMapper.class)
public class ComponentMapperTransplant<A> { 

    @Graft.Prepend
    public A create(int entityId) {
        LifecyclePlugin.dispatcher.onComponentPreCreate(world, entityId);
        A result = create(entityId);
        LifecyclePlugin.dispatcher.onComponentPostCreate(world, entityId);
        return result;
    }
}

@DaanVanYperen
Copy link
Collaborator Author

DaanVanYperen commented May 15, 2019

Just as a final challenge to the pro/cons, this implements something to circumvent our own final classes which we control. And is admittedly cool.

@junkdog
Copy link
Owner

junkdog commented May 15, 2019

I suspect I'm not getting the limitations or how this circumvents singleton (isn't that what StaticDebugEventTrace would be?)

Well, you could inject - either relying on world.inject or manually setting up the listeners in initialize() or the constructor. The static approach - or your dispatcher - is easier though.

@Graft.Mock is perhaps a better name than @Graft.Skip;

@Graft.Target(EntityEdit.class)
public class EntityEditTransplant
       // all calls to `cm` will refer to EntityEdit.cm after  transplant.
       // signature must match, but anything goes (i think)
	@Graft.Mock private ComponentManager cm;

	@Graft.Prepend    
	public EntityEdit remove(ComponentType type) {
		System.out.prtintln(cm.toString()); // accessible thanks to mock
		return remove(type);
	}

How flexible is this? Would this be legal?
`*** perfectly legal code ***

Yes! When a method is Graft.Prepend:ed, the original method is renamed by appending '$actual` to the name. So, in the remove case, "remove$actual(...)". When grafting a method, all "recursive calls" are translated so that they instead point to the original, "$actual" method. So, you're free to call the $original or opt out completely.

this implements something to circumvent our own final classes which we control. And is admittedly cool.

:yak: 😄

@DaanVanYperen
Copy link
Collaborator Author

Pfew this is becoming quite a scroll! I wonder if tickets cap at 100 comments.

@DaanVanYperen
Copy link
Collaborator Author

PoC done! :) Just need to pivot subclasses to @Grafts.

image

@DaanVanYperen
Copy link
Collaborator Author

Debug plugin is finding issues in Jam library i've been using for years.

(delete component after entity.removeFromWorld).

*********************
MediumblueLeafcutterant(238) ERROR_ATTEMPT_TO_ACCESS_DELETED_ENTITY @ net.mostlyoriginal.api.plugin.extendedcomponentmapper.M.remove(M.java:146)
       .. net.mostlyoriginal.api.plugin.extendedcomponentmapper.M.remove(M.java:156)
       .. net.mostlyoriginal.api.system.SchedulerSystem.process(SchedulerSystem.java:31)
Caused by ENTITY_DELETE at:
MediumblueLeafcutterant(238) ENTITY_DELETE @ net.mostlyoriginal.api.operation.basic.DeleteFromWorldOperation.process(DeleteFromWorldOperation.java:19)
       .. net.mostlyoriginal.api.operation.common.BasicOperation.process(BasicOperation.java:16)
       .. net.mostlyoriginal.api.operation.flow.SequenceOperation.nextOperation(SequenceOperation.java:37)
       .. net.mostlyoriginal.api.operation.flow.SequenceOperation.process(SequenceOperation.java:25)
       .. net.mostlyoriginal.api.operation.flow.ParallelOperation.process(ParallelOperation.java:22)
       .. net.mostlyoriginal.api.system.SchedulerSystem.process(SchedulerSystem.java:29)
*********************```

DaanVanYperen added a commit that referenced this issue May 18, 2019
…ory to support editor and debugger plugins.

- New extension point for debuggers and editors. (`InternalFactory`)
- New lifecycle phase listener for debuggers and editors (`ArtemisPhaseListener`).
DaanVanYperen added a commit to DaanVanYperen/artemis-odb-contrib that referenced this issue May 18, 2019
…ssues.

** Builds against https://github.com/junkdog/artemis-odb/tree/feature-570-lifecycle-poc

- *New plugin `contrib-plugin-lifecycle-listener`*
  - Allows listening to odb component, entity and other lifecycle events.
- *New plugin `contrib-plugin-debug`*
  - Allows debugging those nasty 'entity id' issues.
  - Can log entity lifecycle events like create, delete.
  - Can also log errors (accessing/deleting already deleted entities) and report a stacktrace to the cause.
  - Usage (pick one you like):
       `WorldConfigurationBuilder.with(DebugPlugin.thatLogsErrorsIn("net.mostlyoriginal"))`
       `WorldConfigurationBuilder.with(DebugPlugin.thatLogsEverythingIn("net.mostlyoriginal"))`
       `WorldConfigurationBuilder.with(new DebugPlugin(new MyDebugLogStrategy()));`
@DaanVanYperen
Copy link
Collaborator Author

Mostly done. Only grafting & fix debug plugin reporting listeners interacting with deleted entities as errors.

DaanVanYperen added a commit that referenced this issue May 18, 2019
DaanVanYperen added a commit to DaanVanYperen/artemis-odb-contrib that referenced this issue May 18, 2019
…emoval.

- Debugger treats creating components on deleted entities as a bad practice and reports it as an error.
- Debugger treats all other component interactions legal on @DelayedEntityRemoval until deletion is finalized.
DaanVanYperen added a commit to DaanVanYperen/artemis-odb-contrib that referenced this issue May 18, 2019
@junkdog
Copy link
Owner

junkdog commented Jun 18, 2019

I should have posted #576 (comment) here instead.

I'll begin replacing the existing ASM code in artemis in the coming days (away over midsummer though). It's pretty sparse on tests, so might be a bumpy ride, but my gut feeling is pretty optimistic.

@DaanVanYperen
Copy link
Collaborator Author

That's one fine looking library! What we could do is if you line the ASM rewrite for 2.4.0, in the mean time I'll rewrite #575 with graft so we can get a release out for the peeps before summer vacation. Think there's a chunk of stuff ready for release https://github.com/junkdog/artemis-odb/blob/develop/CHANGELOG.md

@junkdog
Copy link
Owner

junkdog commented Jun 18, 2019

Thank you! Very happy with how this turned out. Still some rough edges of course (better validation, both agent and maven plugin could use some extra configuration etc), but code is pretty clean/easy to extend.

Yeah, wise to delay the ASM rewrite for 2.4.0. We're not adding any functionality to that layer anyways, and like you said - the changelog is growing.

@junkdog
Copy link
Owner

junkdog commented Jun 20, 2019

WIP on integration tests-as-recipes for the agent: figured they could be recycled on the wiki.

https://github.com/junkdog/graftt/tree/master/agent/src/it/agent-no-params/src

@junkdog
Copy link
Owner

junkdog commented Jun 24, 2019

deployed latest graftt -SNAPSHOT + begun writing a more in-depth guide on the wiki

@intrigus
Copy link

Hey, I'd love to try this to debug some issues I have.
But I can't get it running.
compile "net.mostlyoriginal.artemis-odb:contrib-plugin-debug:2.5.0-SNAPSHOT" doesn't work ("Could not resolve: net.mostlyoriginal.artemis-odb:contrib-plugin-debug:2.5.0-SNAPSHOT").
I cloned artemis-odb-contrib checked out the develop branch and did mvn clean install but this also fails.
With similar errors as travis ci is having https://travis-ci.org/DaanVanYperen/artemis-odb-contrib/builds/534237090#L2047
Is there any way to try this plugin?

@junkdog
Copy link
Owner

junkdog commented Aug 14, 2019

@intrigus Daan needs to merge/review DaanVanYperen/artemis-odb-contrib#130 first - it should work if you mvn install from the lifecycle-graftting branch on junkdog/artemis-odb-contrib

@junkdog
Copy link
Owner

junkdog commented Aug 14, 2019

@intrigus DebugPlugin.isArtemisTransformedForDebugging() returns true if the lifecycle stuff is transplanted/setup.

@intrigus
Copy link

intrigus commented Aug 14, 2019

I got it compiling with Java 8.
It doesn't compile with Java 11:

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.1:compile (default-compile) on project contrib-plugin-debug: Compilation failure: Compilation failure:
[ERROR] /home/deb-ban/artemis/artemis-odb-contrib/contrib-plugin-debug/src/main/java/net/mostlyoriginal/plugin/DebugSystem.java:[8,16] cannot find symbol
[ERROR] symbol:   class SharedSecrets
[ERROR] location: package sun.misc
[ERROR] /home/deb-ban/artemis/artemis-odb-contrib/contrib-plugin-debug/src/main/java/net/mostlyoriginal/plugin/DebugEventStacktrace.java:[4,21] package org.omg.CORBA does not exist
[ERROR] /home/deb-ban/artemis/artemis-odb-contrib/contrib-plugin-debug/src/main/java/net/mostlyoriginal/plugin/DebugSystem.java:[207,55] cannot find symbol
[ERROR] symbol:   variable SharedSecrets
[ERROR] location: class net.mostlyoriginal.plugin.DebugSystem
[ERROR] /home/deb-ban/artemis/artemis-odb-contrib/contrib-plugin-debug/src/main/java/net/mostlyoriginal/plugin/DebugSystem.java:[212,44] cannot find symbol
[ERROR] symbol:   variable SharedSecrets
[ERROR] location: class net.mostlyoriginal.plugin.DebugSystem
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
[ERROR] 
[ERROR] After correcting the problems, you can resume the build with the command
[ERROR]   mvn <goals> -rf :contrib-plugin-debug

@junkdog
Copy link
Owner

junkdog commented Aug 14, 2019

I got it compiling with Java 8.
It doesn't compile with Java 11:

Thanks. Pushed an untested fix, removing usage of SharedSecrets and the unused corba import.

@DaanVanYperen
Copy link
Collaborator Author

I'm happy how graftt turned out on contrib. Thanks for that @junkdog! Travis build is passing. This ticket is pretty much done, just waiting for some snapshots to release and then we have a go!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants