google-code-export / javasimon

Automatically exported from code.google.com/p/javasimon
BSD 3-Clause "New" or "Revised" License
1 stars 1 forks source link

Attach metadata to Simons #18

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
Our customers love the fact that we can provide great timing reports based 
on JavaSimon, and in particular the Stopwatch. However, they frequently ask 
that we output more information about the object being measured, perhaps 
even with a drill-down facility.

Our simons use syntethic names based on guids, such as 
"contentViewer.AABBCCDDAABBCCDD". The guids are in fact tracable back to 
user level application objects, but it's a bit cumbersome...

Our first desire is to use custom Stopwatch classes, which I'm sure we can. 
Then we can code like this:

   CustomStopwatch stopwatch = manager.getStopwatch("contentViewer.GUID");
   if (! stopwatch.isInitialized()) {
      stopwatch.setReadableName (this.getTitle());
      stopwatch.setObject (this);
   }

However, we really want different Stopwatch classes for different 
Stopwatches. Our "contentViewer.GUID"-stopwatches are backed by a 
ContentViewer-object, with some needs. "ldapConnection.GUID" are backed by 
an LDAPConnection-object, with others. So we want these two to return 
different types:

   Object sw1 = manager.getStopwatch ("contentViewer.GUID")
   Object sw2 = manager.getStopwatch ("ldapConnection.GUID")

... and that just isn't reasonable. Except, perhaps, with interfaces like 
this:

   interface StopwatchFactory {
      Stopwatch createStopwatch(String name);
   }

   interface Manager {
      ...
      Stopwatch getStopwatch (String name, SimonFactory factory);
   }

and then our code like this:

   // The factories may be inner classes, who can reference
   // the required information to create a "full" stopwatch
   manager.getStopwatch ("viewer.GUID", viewerStopwatchFactory);
   manager.getStopwatch ("ldap.GUID", ldapStopwatchFactory);

So, in the end, a couple of questions:

1) Do the requirements make sense?
2) Does the proposed solutions make sense?
3) If not, is there an alternative, or how do we improve it?

If you want to, I can implement some sample code to test this out.

Original issue reported on code.google.com by eirik.ly...@gmail.com on 19 Feb 2010 at 7:22

GoogleCodeExporter commented 9 years ago
And this is *obviously* not a defect, but I can't find a way to set the type...

Original comment by eirik.ly...@gmail.com on 19 Feb 2010 at 7:23

GoogleCodeExporter commented 9 years ago
For various reasons I'd keep this out of Simon if possible. When we started we 
even
experimented with customizable Stopwatches, but in the end we denied the whole 
idea
because there were some low level issues when we wanted to preserve manager 
disabled
mode. Maybe there is now nothing that prevents this, but I honestly doubt it:
- what do you need custom class for? what are typical extensions?
- how much do you want to expose existing inner code?

I don't see your points with all details now, but can't this be solved fully as 
a
separate layer in the application? Maybe some map to custom metadata objects? I 
know
it is coding you have to do (and probably did), but for simplicity sake I'd not 
put
it into Simon.

If I miss something, just add to your explanation.

Original comment by virgo47 on 19 Feb 2010 at 7:57

GoogleCodeExporter commented 9 years ago
Our application runs in a java container. It has an engine which can be asked 
to 
render a page. The engine then loads configuration from a database table, where 
the 
most important item is a list of components to render. A component includes a 
class 
name used to render that component. In many cases it also contains the URL to a 
page 
where this particular component can be configured.

The page engine uses javasimon Stopwatches to track performance. In order to 
distinguish the various components from each other, it uses the database 
primary key 
as part of the simon name. Hence, a real-life stopwatch name is 
"page.component.7FA7C4580C4B3084E040000A18002388.render".

Then we have a management page which exposes a table of stopwatch data in a web 
interface. The table has a couple of columns: Stopwatch name, Count, Average, 
Min, 
Max. The usual stuff. Of course, the stopwatch name is the not-so-friendly 
"page.component.7FA7C4580C4B3084E040000A18002388.render". Therefore, we print 
the 
following note above the table: "In many cases, the monitor name contains a 16-
character long code (a GUID). Most often this is the identity of an object 
defined in 
the database, so this may be useful in identifying which components are 
involved in 
the various operations."

This means that the users have to search through a database table to find a 
GUID, 
look up a component type and title, and then open the right development tool to 
view 
the component definition. Now, a much better way would be for the management 
tool to 
augment the stopwatch name with a human readable name ("List of Personal 
Workspaces 
with open issues"), and to add a "configuration tool" link that opens the 
proper 
tool.

The challenge of today is this:

* The management tool does not know anything about the components; in fact, it 
does 
not even know that there *are* components :-). Hence, the management tools is 
currently unable to show the extra information
* We could let the managment tool understand components, basically parsing and 
understanding the stopwatch names. In addition to breaking isolation and 
relying on a 
brittle strategy (what happens when we need to change simon names?), we would 
have to 
go to the database for every stopwatch, looking for the right information.

Hence, what I would like to see is this: A way to associate custom data with a 
Stopwatch, populated at the time of stopwatch creation.

So, a couple of possible solutions:

1) Todays API, and a separate map of objects. Add synchronization as required. 
Add 
cleanup code.

   Stopwatch sw = manager.getStopwatch (name);
   CustomData d = customDataMap.get(sw);
   if (d == null) {
      d = new CustomData(...);
      customDataMap.put(sw,d);
   }

2) Add metadata-support to the StopWatch. Simple to use, but at the cost of an 
object 
reference for every stopwatch, whether in use or not. Which may not be a lot: 
4K 
memory for 1000 stopwatches; 4M for a million. Of course, it would be very 
simple to 
use, and very unintrusive.

   Stopwatch sw = manager.getStopwatch (name);
   if (sw.getCustomObject() == null) {
      sw.setCustomObject (new CustomData(...));
   }

3) Subclassing the Stopwatch, and having mechanisms allowing me to create the 
proper 
class (the original proposal). I don't understand the internals enough to 
understand 
the downsides, maybe except the cost of passing an extra parameter into the 
functions:

   Stopwatch sw = manager.getStopwatch (name, factory);

4) Extending the callback mechanism, and using that to populate the separate 
map of 
objects. Note that today's callback mechanism is not strong enough, because the 
local 
context is not available. However, that could probably be done:

   Stopwatch sw = manager.getStopwatch(name, new CallbackSkeleton() {
      public void simonCreated (Simon simon) {
         customDataMap.put (simon, new CustomData(...));
      }
   });

5) Finally, maybe, we could customize the javasimon code and compile a private 
version. It would probably be simple, but we still don't want that :-)

6) ...and of course, there are other ways I haven't thought of yet...

The structure of a separate map of objects is unattractive enough that I'd 
really be 
considering going with a private javasimon version. If we need to go there, 
maybe we 
could look at ways of doing that with as little intrusion as possible, to make 
this 
as low cost as possible?

Original comment by eirik.ly...@gmail.com on 20 Feb 2010 at 12:27

GoogleCodeExporter commented 9 years ago
As I write, I think of ways to make the custom java implementation as cheap as 
possible -- maybe even find a way to make the javasimon 
code easily "hackable". And the following should do nicely -- we would not have 
to edit the javasimon source code to make the required 
changes. Which would be very nice :-)

   public final class EnabledManager implements Manager {

        // Same for counter
        static public Class<? extends AbstractSimon> stopwatchClass = StopwatchImpl.class;

        public Stopwatch getStopwatch(String name) {
               // return (Stopwatch) getOrCreateSimon(name, StopwatchImpl.class);
               return (Stopwatch) getOrCreateSimon(name, stopwatchClass);
        }
   }

Original comment by eirik.ly...@gmail.com on 20 Feb 2010 at 12:42

GoogleCodeExporter commented 9 years ago

Original comment by virgo47 on 1 Mar 2010 at 7:20

GoogleCodeExporter commented 9 years ago
This is marked as fixed, but what actually changes in javasimon 2.3.0, it's not 
obvious from reading the ticket.

Original comment by dirous...@gmail.com on 27 Jul 2010 at 12:48

GoogleCodeExporter commented 9 years ago
Sorry for confusion. Four methods are added to Simon interface:

java.lang.Object    getAttribute(java.lang.String name)
java.util.Iterator<java.lang.String>    getAttributeNames()
void    removeAttribute(java.lang.String name)
void    setAttribute(java.lang.String name, java.lang.Object value)

http://javasimon.googlecode.com/svn/javadoc/api-2.3/org/javasimon/Simon.html

There is no additional magic to this. Attributes are mere storage (as in HTTP 
request/session or similar), and it's up to you what to do with them and when.

Original comment by virgo47 on 27 Jul 2010 at 1:07

GoogleCodeExporter commented 9 years ago

Original comment by virgo47 on 29 Dec 2011 at 6:03