We are moving to Git Issues for bug tracking in future releases. During transition, content will be in both tools. If you'd like to file a new bug, please create an issue.

Bug 8015 - Consolidate article level statistics plugins and put in core
Consolidate article level statistics plugins and put in core
Product: OJS
Classification: Unclassified
Component: General
All All
: P3 normal
Assigned To: PKP Support
Depends on:
  Show dependency treegraph
Reported: 2012-11-09 13:09 PST by Matthew Crider
Modified: 2014-03-31 07:13 PDT (History)
5 users (show)

See Also:
Version Reported In:
Also Affects:


Note You need to log in before you can comment on or make changes to this bug.
Description Matthew Crider 2012-11-09 13:09:07 PST
The COUNTER and Timed Views plugins can be consolidated, enhanced, and put into pkp-lib. 

Other notes:
-With this, we can remove the views count from the article_galleys table
-Ensure proper indexing of the view log table and make sure it scales well
-Look into using a bot list from an official source (e.g. AWStats)
-Integrate geolocation (Matt has done country tracking, can add a separate column for city)
Comment 1 James MacGregor 2012-11-30 15:03:57 PST
From discussions with Coaction: 

There needs to be a clear idea, for any statistic that is gathered/displayed in OJS, of the following: 

-- what kind of filters/exclusions are applied to the statistic (COUNTER bots filter; internal OJS bots filter; only x views per x seconds allowed; etc.)
-- if it is an aggregated count (for example a general article view count that sums abstract & galley counts), how the aggregation is calculated
-- optionally, stats collection/generation frequency (if somehow applicable)
-- optionally, which discovery options are available (publicly on website; via SUSHI; etc.)

Areas where view counts are available: COUNTER plugin; Timed Views plugin; original View report, if not deprecated; the views available to Editors next to each galley in editing and to authors on their Archived Submissions page; and probably the Most Viewed Articles plugin

Proposed steps to unify/clarify/simplify view stats generation:

1. Create a proper, separate and **unfiltered** view log table (migrating/moving the view count from the article_galleys table, as above), containing (list subject to discussion): 
- submission ID
- galley ID (if applicable)
- maybe galley type (if applicable)
- date/time
- remote IP address/domain
- referrer URL
- user agent
- geolocation

2. Create individual methods in lib/pkp to perform the various **general** filter mechanisms we would typically expect stats/report plugins to be able to call upon, such as:
- an exclusionList function (to use the bot list, lib/pkp/registry/botAgents.txt from Bug 7684 by default);
- a limitViewIncrementByTimespan function, to not increment a view count if a particular galley has been viewed more than x times/second from the same IP address;
- some sort of getStatsReportInfo function that will provide all filters currently applied to the report, and the date the report was generated (along with any other relevant info);
- a limitByDateSpan function, so that plugins could specify a date range for stats generation;
- optionally (and probably out of scope) abstract the report **generation** functions into separate xml, csv and possibly HTML table options'
- other?

3. Ensure that plugins can extend/add to the above functions individually; for example, the COUNTER plugin should almost certainly include its own exclusion list (see http://www.projectcounter.org/documents/COUNTER_robot_txt_list_Jan_2011.txt for the R3 version). 

4. Clean up the plugins to adhere to a set of conventions, such as:
- if providing a file for download, always include the file generation date/time in the filename, optionally in the file header;
- provide all other filter/report info (bot agent filters used; date span of report; etc.) somewhere, not necessarily in the report itself.
Comment 2 Alec Smecher 2012-12-10 11:17:33 PST
I think we need a clear proposal on how to deal with log accumulation. It's a problem that's dogged us for a long time -- either we've not solved the problem (the initial COUNTER implementation, which used a flatfile that torpedoed analysis by rapidly growing beyond PHP's ability to read it) or gone too far in avoiding it entirely (incrementing counters that are quick to read/write but not auditable and lead to breaks in comparable stats when the details change e.g. around what bots are excluded).

Should we store these exhaustively in the DB? Should they be stored with indexes (relatively slow to insert) or without (slow to analyze)? What should our policies be around log growth, and how should we reflect those in log maintenance tools?
Comment 3 jerico 2013-01-08 09:28:46 PST
Just for documentation here our specific API proposal that IMO works across all requirements I've seen so far (including the ALM project). You received it in October by email already. I comment on all proposals made in this bug report below.

The proposal is for integration of OJS with the Open Access Statistics (OAS) including changes to core OJS for cross-statistics requirements.

Roughly it will function like this: OJS will track the access on issue galleys, abstracts, galleys and supp files (similar to the apache format "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\""). Those data will be provided via the OAI interface (as ContextObjects) and harvested by OAS service provider (OAS-SP), i.e. there will be another OJS OAI interface for these data.

When harvested the data will be deleted.

OAS-SP will compute and provide the usage statistics (at the moment according to the COUNTER, but later maybe also LocEc, IFABC) on a daily basis. OJS gets the usage statistics and uses them in different ways:
-- they will be displayed to the authors and editors (in the same/similar way as till now),
-- they will be displayed to the readers,
-- they will be combined with the search (as a sort criteria),
-- report will be created,
-- there will be the feature "most viewed articles",
-- there will be the feature "another (more viewed) articles of the same author",
-- there will be the feature "similar (more viewed) articles".

These use cases require us to integrate various usage statistics (OAS,
COUNTER/OJS, ALM). Thus, Florian and I (Bozana) thought about an internal data model that would enable us to implement these use cases. We therefore propose a new DB table 'metrics' that contains all metric data:
-- document ID
-- document type
-- date
-- metric (e.g. "OAS", "COUNTER", "OJS")

There would be a MetricDAO, to save all usage statistics and to get the
filtered statistics (of one or several metrics at the same time, for a
period, for a journal,...).

ReportPlugin could, similar to PubIdPlugin, serve as the metric provider:
-- Statistic plug-ins (e.g. COUNTER, timedView, OAS) should provide a ReportPlugin. If a plug-in needs hooks (e.g. to track the access) it
should be nested in a GenericPlugin.
-- There would be e.g. the following functions: getMetricTypes(),
getMetricDisplayType($metricType), getMetricFullName($metricType). They
could return NULL (in case of the non-statistics report plug-ins, i.e.
articles, reviews, subscriptions).
-- There would be also getMetric($metricType, $pubObject,
...filter...)/getAllMetrics($metricType, $pubObject, ...filter...).
I.e. the MetricDAO would be used to store and get all the metrics and
the functions getMetric and logMetric would be implemented in the
ReportPlugin basis class. Thus, there would be no need for an extra DB
table, DAO and functions pro every statistic plug-in any more.

Article/ArticleGalley/IssueGalley/SuppFile::getViews() would then change
to getMetric($metricType, ...filter...). If no $metricType is given the
main/primary metric type will be used. I.e. if there are several metric
types, there should be a possibility (either for journal manager or
admin) to choose/define the main/primary metric type.
Article/ArticleGalley/IssueGalley/SuppFile::getAllMetrics() would return
an array with all metrics. 

Please help us to review/simplify this proposal if possible! We have to do so relatively quickly, though, as we have to start implementation within the next week or so.

And here my specific comments about the further proposals in this bug report:

1) A common raw-data data source / A clear proposal on how to deal with log accumulation.

I agree that probably neither MySQL nor monolithic flat files are a good idea to keep log data. These solutions do not scale well.

I see the following options:
- Work with a stats provider like ALM or OA-S and get rid of the requirement to provide an audit trail ourselves.
- Work with an optional, scalable data store, e.g. a NoSQL DB to log data and provide a scalable interface to load data back from that source if necessary
- Keep an external audit trail in log files (e.g. web server logs) and provide a proper re-startable loading mechanism similar to what is done in the Data Warehouse-World. We've implemented this for scalable re-indexing in Lucene and it works great even with large OJS installations (=pull indexing, see the Lucene plug-in README).

In our case (OA-S) we use the first option so we won't have to solve this problem.

If several plug-ins need common historical raw view data (which is not our case) then it certainly makes sense to share them in a single appropriate, scalable data source.
If I understand this correctly then after the proposed plug-in consolidation there'll only be one stats plug-in left in OJS that needs raw historical data. I understand that an audit trail inside OJS is important for the OJS stats but that's something specific to that plug-in.

Storing raw data by default is difficult for other reasons, too: It is simply not allowed to store raw data containing IPs in Germany and other countries (privacy legislation). The same may be true for more complex combinations of data records that can reveal the identity of the user, e.g. by application of statistical methods.

I therefore don't think, that storing raw data is something that should be solved via the core OJS API (plug-in API). I think that an extension, documentation and standardization of the current shared "statistics-event-based" view source (=hook) is better suited to serve the needs of different stats plug-ins. Plug-ins can subscribe to the raw data feed on the lines of an Apache log and do whatever they like with that data (e.g. immediately anonymize it).

I think that a shared table is possible on the aggregate metrics side, though (see the proposed metrics table above). I believe that this works as the format of such a table will be dictated by the OJS front-end integration use cases which are the same for all stats plug-ins. The number of data items in such a table will be way less than that of the raw data source. If we reach MySQL scalability limits we could still purge old metric data or keep it only at a more consolidate level.

Such a common table won't be useful for ALM or other stats providers that will not systematically send back aggregate metrics at all. If such a shared table exists it should not be mandatory and not assumed to be complete. It could just be an available infrastructure that statistics plug-ins can use if they like so that we avoid excessive growth of the data model (one or more new tables for every new metric).

Some of our requirements actually force us to have a common API to all metrics, so that we can display them side-by-side, regardless of the statistics source/provider. The proposed plug-in-level API is fully compliant with ALMs requirements and implementation as far as I understand it so far. This is much more flexible than a shared table and seems to be the right level of abstraction seeing the currently known requirements.

2) "various **general** filter mechanisms"

I think that's difficult. Every statistics definition/statistic provider will impose different filtering mechanisms. Maybe we better leave this kind of implementation detail inside the plug-in's black box?

3) limitViewIncrementByTimespan

This is COUNTER-specific. IMO the time-spans and exact implementation details will differ depending on the stats definition. Putting this in a public API would not be the right level of abstraction IMO. It's a good idea, though, to remove the duplicate code across plug-ins by the simple application of the DRY rule. That's why we proposed the consolidation of the two plug-ins in the first place.

4) getStatsReportInfo

I think that could work well across all stats providers. We don't have such a requirement but I don't see why such a thing could not be implemented in ReportPlugin as we proposed it above. It could be a simple free text that may appear in appropriate places on the public web site similarly to what we do with editorial information.

5) limitByDateSpan

We address this in our API proposal. Report plug-ins can use the proposed API to retrieve metrics limited by date span. Our API is just a bit more general than that to address all currently known reporting use cases (e.g. filtering by journal, reports across metrics, etc.).

6) Abstract the report **generation** functions into separate xml, csv and possibly HTML table options'

I think I didn't understand this. We want to provide a common metrics data access model that makes it possible to create all report types that I know of so far. It may be possible to share a lot of code between reports once we have a common API to access statistics. I think it will also be possible to completely get rid of stats-specific reports and provide a more general reporting engine (or much better even: use an existing one). But that's out-of-scope for our project. We'll simply add the new reports that we have to implement and avoid code duplication for those as far as possible.

7) Ensure that plugins can extend/add to the above functions individually

Are there specific examples/use cases/requirements? Or is this just a general observation?

8) Conventions for plug-ins

- if providing a file for download, always include the file generation date/time in the filename, optionally in the file header;

Seems to be a very specific requirement that could be extracted and implemented as a separate bug report. I can make sure that our reports will include such information.

- provide all other filter/report info (bot agent filters used; date span of report; etc.) somewhere, not necessarily in the report itself.

Seems to be adressed by getStatsReportInfo() above.

I'll later consolidate this loooong comment into our OA-S spec with a nicer structure etc. I wanted to make you aware, though, of where we stand right now with our requirements and thoughts.
Comment 4 beghelli 2013-01-14 09:43:55 PST
Chatting with Florian about this proposal made me suggest that we can use assocType and assocId to identify the publication object. It's clearer because we already use this in many other places and also it's generic enough.
Comment 5 beghelli 2013-01-14 09:54:49 PST
Following the idea above, we might have:

-- assocId instead of document id;
-- assocType instead of document type;

Also, chatting with Bozana, she told me that we might need a column for the metric value itself, not only the metric type (Counter, OAS, etc).

So I think that we might end up with this model:

-- assocId
-- assocType
-- date
-- metric (e.g. views count)
-- metricType (e.g. "OAS", "COUNTER", "OJS")
Comment 6 jerico 2013-01-14 10:21:01 PST
I like Bruno's idea of using assocId/Type as this is much more in line with prior use in OJS and makes it much clearer what documentId means.

It is true that Bozana only gave a list of /dimensions/ and not the full metric table. I'd rather stick to the name 'metric' for the metric name and use 'fact' or 'value' for the numbers, instead, as this is more or less standard in the OLAP/statistics world.

What's been omitted as well from our original proposal are the aggregation hierarchies (e.g. time: month->year), etc. These will probably not have to be implemented in tables as either tables already exist or aggregation can easily be made "on the fly". Nevertheless conceptually we are proposing a multi-dimensional OLAP cube with the following dimensions:

conceptual ground dimensions:
1) unique ID of the publication object (assocId + assocType)
2) date (day)
3) metric ("COUNTER", "OA-S", "ALM-Facebook", ...)

conceptual aggregation hierarchies over the ground dimensions:
1) assocId/Type: assocType itself aggregating several assocIds
2) author
3) month -> year
4) article -> issue -> journal  (as aggregation criteria, not the objects themselves)

The "fact" column would be a single integer or float field for the actual metric data. This column must be "additive" if we want to use it in reports that "slice" and "dice" the cube. This excludes "from-to" notation for the date. Monthly data that is not available on a daily basis can be modeled additively in such a table by introducing a month-ID to the metrics table and leaving the day-ID empty.

This is pretty much a standard OLAP design and should therefore serve all aggregate data needs that may come up in reports or elsewhere. The rest of the API (getMetric, etc.) serves "granular metric access" purposes, e.g. when displaying metrics data for a single article or for a few articles (e.g. in search). I assume that plug-ins that do not store data locally (ALM!) will not be able to do reporting as retrieving large amounts of raw data on the fly over the web will be too slow (unless ALM provides aggregate data over the wire, too).
Comment 7 Alec Smecher 2013-01-14 16:55:15 PST
Florian/Bozana -- it sounds like one of the next steps will be consolidate these details into your spec. So far I agree with the motivations and ideas exchanged here, though it's a little dense at the moment to grok properly. The high proximity of the log storage to the Apache log format makes a few options possible:

1) Optionally delegating log events to a CLF storage that's maintained by the web server, with logfiles generated by OJS made possible via a plugin
2) Along those lines, moving part of the stats maintenance outside of OJS entirely -- OJS becomes a statistic consumer and little else.

Broadly, though, I support the direction this discussion is going. I'm slightly worried about the potential complexity, though we've seen what happens with partial solutions -- they multiply and result in poor quality stats.
Comment 8 jerico 2013-01-14 18:41:40 PST
Hi Alec,

I started the OA-S spec today, see <http://pkp.sfu.ca/wiki/index.php/OJSdeStatisticsConcept#Data_Extraction_and_Storage>.

You are right: It would be great if we could keep the whole log parsing, etc. out of OJS. This is especially true as most stats solutions will by default work with Apache logs ootb. In the case of OA-S for example there already is an existing solution that could parse Apache logs.

U Berlin currently has a design requirement, though, to keep everything concerning OA-S within OJS (i.e. PHP) so that we can avoid any kind of extra installation requirement and the solution "just works" (after enabling the plug-in). @Bozana: I hope I'm seeing this correctly?! Can you confirm this?

I'm proposing the stats event hook inspired by Apache's info items simply because it will automatically give us data close to what OA-S and other statistic standards (COUNTER) expect.

WRT complexity: I agree. We shouldn't try to put anything in here that doesn't directly correspond to a requirement we have now and here.
Comment 9 jerico 2013-01-15 09:54:38 PST
> I'd rather stick to the name 'metric' for the metric name and use 'fact' or
> 'value' for the numbers, instead, as this is more or less standard in the
> OLAP/statistics world.

I have to withdraw this comment as this would be inconsistent with the API proposed by Bozana and myself where we already use the getMetric/getMetricType nomenclature. Using getFact() would be too generic for my taste and make it unclear what is actually meant by a "fact".

Thinking about it like this I prefer Bruno/Bozana's proposal to call the table columns "metric" and "metricType" which is perfectly in line with the proposed plug-in API.
Comment 10 jerico 2013-01-15 11:24:53 PST
I just finished the specification of the API part that has been discussed here:


That should consolidate all our comments as well as feedback from Bruno and Alec so far. We still need Juan's promised commitment to the API for ALM. It's also still unclear whether Juan will support the MetricDAO or not.

Now we need to coordinate who will do what. I propose the following:

* I do the basic implementation of the plug-in API and the MetricDAO + table within the next few days (at most one week after PKP - especially Juan - commits to the API).

* Bruno consolidates the OJS view plug-ins and the reporting engine. If I understood his current assignment correctly then he'll have to work on both anyway.

* Juan implements the plugin API for the ALM plug-in and the display of granular metrics to readers, editors and authors (which was his own proposal).

* I'll implement the OA-S plug-in as specified in the document linked here as well as implement all the additional front-end requirements (see the spec) that will benefit not only OA-S but all statistics, including OJS views and ALM. NB: ALM will only benefit from use cases that use granular data if the MetricDAO will not be implemented by this plug-in.

Do you agree to that? Counter proposals?
Comment 11 jerico 2013-01-17 09:54:01 PST
I just added the big magic statistics API to the base ReportPlugin class. :-) See here: https://github.com/jerico-dev/ojs/commit/c6df1923b02c73a3724473a32c433cc404016123

As you can see in the comments, the statistics spec gives a detailed specification of the input and output values.
Comment 12 Alec Smecher 2013-01-17 09:56:44 PST
Florian: about the option to use internal vs. externally-maintained logfiles. If we stick to CLF, then OJS maintaining its own logfiles becomes an option. For our own hosting operations (and for anyone else not using shared hosting, I suspect) delegating logfile maintenance to the existing toolset is a major advantage. Would coding the logfile maintenance part of this as a plugin suit your purposes? That way both internal and external approaches would be viable without any extra fuss.
Comment 13 jerico 2013-01-17 10:30:27 PST
Hi Alec, I've got nothing at all against implementing usage event collection with a plug-in.

I'm just not clear, how that plug-in should look (methods, signatures), in which category it should be placed, how the event propagation (hooks?) or interfacing with report plugin works, etc.

You have to keep in mind that the raw usage events I need and the ones needed for the COUNTER plug-in are very similar (as OA-S is an "almost-COUNTER" implementation). So it would be great to have them in one place only. Whether this is a common hook or a plug-in doesn't matter to me.

Can you specify this a bit more? Preferably in a way that I can implement it without having to do the design myself?

If this takes a bit of time on your side I don't mind either. I can implement the usage event collection as a hook for the moment being. I'll make sure that moving the logic to a plug-in will be a matter of minutes. I'can do this once I got the spec for it.
Comment 14 Alec Smecher 2013-01-17 10:32:50 PST
My thought was that OJS could use CLF logfiles, either those maintained by the webserver, or those maintained by a generic OJS plugin. However, I suspect that falls afoul of the privacy laws that you mentioned earlier. When maintaining a webserver in line with those requirements, how is the server's logging configured?
Comment 15 jerico 2013-01-17 12:07:06 PST
Just a heads-up for Bruno (and maybe Alec): I'm not sure but to me it looks as if the COUNTER plug-in did double counting of usage events in certain cases. Once for the interstitial/article page and once for the actual download of the file. Is that correct?

In the case of OA-S this would be wrong.

I didn't check the OJS views plug-in.
Comment 16 jerico 2013-01-17 12:20:20 PST
Re my last comment: Here's the OA-S definition of what I consider usage events for the different publication objects.

Comment 17 jerico 2013-01-17 13:03:47 PST
Non-pseudonimized webserver logs (i.e. containing the IP) would have to be deleted immediately (i.e. as soon as the pseudonimization has taken place). The privacy report I'm basing my spec on mentions "about five minutes" as their definition of what would be "immediately".

In any case: If we give users the alternative to use one usage event plug-in or the other, we could advise OA-S users to base their statistics on my usage event plugin which will not log anything but only produces a stream of usage events that can immediately be "forgotten" after pseudonimizing them.

That's why I proposed that any log source should be implemented as a event source rather than providing a permanent event store and leave it up to the plug-in to store events (or not).
Comment 18 jerico 2013-02-07 17:31:55 PST
Ok, as I didn't get any further feedback and had to move on I implemented event collection the "classic" way, i.e. with existing hooks.

I cleanly isolated event collection code and implemented it in a generic way which goes beyond what we actually need. This makes it very easy to factor event collection into a plugin at a later stage. I also provide a 1:1 comparison with Apache log standards as an extensive inline comment, see here:


We also decided not to push the plug-in to core OJS as it'll not be of any relevance outside Germany. We'll rather contribute it via the plugin gallery.

The statistics API has been fully implemented in the report plugin base class as already mentioned. @Juan, Bruno: If you have any further questions re implementation or specification of the API, please let me know and check what I've written on the wiki page.

Plugin code can be reviewed here:

Comment 19 beghelli 2013-03-26 18:25:01 PDT
Statistics integration fixes
Comment 20 beghelli 2013-03-26 18:30:02 PDT
Introduced file loader base task class
Comment 21 beghelli 2013-04-04 09:10:02 PDT
Added geo localization dimensions
Comment 22 beghelli 2013-04-04 09:15:02 PDT
Introduced usage stats plugin
Comment 23 beghelli 2013-04-04 09:15:02 PDT
Introduced usage stats plugin library for geolocalization
Comment 24 beghelli 2013-04-12 14:15:04 PDT
Redirect to view operation when current is called
Comment 25 beghelli 2013-04-15 21:40:02 PDT
Ignore geolocalization data file
Comment 26 beghelli 2013-04-15 21:40:02 PDT
Introduced plugin that implements a hook to provide usage event
Comment 27 beghelli 2013-04-18 08:10:02 PDT
Build usage event on issue main page views
Comment 28 beghelli 2013-04-25 15:10:02 PDT
Catch files and galleys views
Comment 29 beghelli 2013-04-25 15:10:03 PDT
Added regex to parse plugin log files, add url to track issue views
Comment 30 beghelli 2013-04-25 15:10:03 PDT
Added issue statistics database insertion case
Comment 31 beghelli 2013-05-01 07:15:04 PDT
Fixed function name in IssueGalleyDao calls
Comment 32 beghelli 2013-05-01 07:20:02 PDT
Fixed memory leak in DAORegistry
Comment 33 beghelli 2013-05-02 12:37:28 PDT
Store region and city geolocalization data in metrics table
Comment 34 beghelli 2013-05-02 12:37:29 PDT
Count article or issue view when no galley is found
Comment 35 beghelli 2013-05-02 12:37:29 PDT
Still removing code related to view columns
Comment 36 beghelli 2013-06-03 08:17:03 PDT
Move code to find bots to core and make the bot file a parameter
Comment 37 beghelli 2013-06-03 08:17:03 PDT
Add file type dimension
Comment 38 beghelli 2013-06-03 08:17:03 PDT
Let usage events plugin hooks being called after download
Comment 39 beghelli 2013-06-03 08:18:02 PDT
Store region code only
Comment 40 beghelli 2013-06-03 08:20:03 PDT
Filter bots, check access using url and not referer, store region id only, add another article galley url case
Comment 41 beghelli 2013-06-03 08:20:03 PDT
Handle file download finished case
Comment 42 beghelli 2013-06-03 08:20:03 PDT
Avoid counting downloads not yet done, fix plugin locale doc
Comment 43 beghelli 2013-06-03 08:20:03 PDT
Avoid logging unfinished file downloads requests
Comment 44 beghelli 2013-06-04 09:45:03 PDT
Implemented counter and timed views plugins usage stats migration
Comment 45 beghelli 2013-06-04 22:10:03 PDT
Implemented ojs default stats migration scripts and separated the existing stats scripts
Comment 46 beghelli 2013-06-05 10:45:02 PDT
Only retry request if the curl execution response is false (avoid reposting when request is successful but the response is empty)
Comment 47 beghelli 2013-06-05 10:45:02 PDT
Fixed JSON web service
Comment 48 beghelli 2013-06-05 12:00:02 PDT
Added missing dimension constants, moved file type constants to application level
Comment 49 beghelli 2013-06-05 12:01:01 PDT
Return galley factory when retrieving galley by setting
Comment 50 beghelli 2013-06-10 05:36:03 PDT
Moved metric type constants to report plugin
Comment 51 beghelli 2013-06-10 07:04:02 PDT
Moved ojs default stats migration to upgrade class
Comment 52 beghelli 2013-06-10 07:05:01 PDT
Introduced missing metric type constant for stats migration
Comment 53 beghelli 2013-06-20 07:20:05 PDT
Changed journal id to context id, added extra documentation, fixed a postgres issue (cast to int)
Comment 54 beghelli 2013-06-20 07:20:05 PDT
Set the site default metric type when upgrading
Comment 55 beghelli 2013-06-20 07:20:05 PDT
Remove old stats plugins settings when upgrading
Comment 56 beghelli 2013-06-20 07:20:06 PDT
Optimized and fixed issues in stats migration
Comment 57 beghelli 2013-06-20 07:21:02 PDT
Changed journal id to context id
Comment 58 beghelli 2013-06-20 07:21:02 PDT
Fixed metrics schema description
Comment 59 beghelli 2013-07-05 09:08:02 PDT
Fixed usage event plugin for file download cases
Comment 60 beghelli 2013-07-05 09:26:01 PDT
Avoid error if no geo database file is present
Comment 61 Alec Smecher 2013-07-26 10:57:02 PDT
Fix upgrade process for versions not including issue_galleys
Comment 62 beghelli 2013-08-09 10:38:02 PDT
Fixed problems when upgrading twice, introduced needed methods to purge and check stats records
Comment 63 beghelli 2013-08-17 18:08:02 PDT
Avoid migration non existing counter stats if upgrade is executed more than one time
Comment 64 beghelli 2013-08-17 21:11:01 PDT
Fixed hard coded usage of a metric constant value
Comment 65 beghelli 2013-08-20 14:53:01 PDT
Introduced missing locale key
Comment 66 beghelli 2013-08-27 14:33:02 PDT
Added return value and fixed double click filtering counter requirements
Comment 67 beghelli 2013-12-03 19:51:03 PST
Only retry request if the curl execution response is false (avoid reposting when request is successful but the response is empty)
Comment 68 beghelli 2013-12-06 07:46:03 PST
Fixed old counter upgrade