2 * Copyright 2011-2012 GRNET S.A. All rights reserved.
4 * Redistribution and use in source and binary forms, with or
5 * without modification, are permitted provided that the following
8 * 1. Redistributions of source code must retain the above
9 * copyright notice, this list of conditions and the following
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials
15 * provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 * POSSIBILITY OF SUCH DAMAGE.
30 * The views and conclusions contained in the software and
31 * documentation are those of the authors and should not be
32 * interpreted as representing official policies, either expressed
33 * or implied, of GRNET S.A.
36 package gr.grnet.aquarium.store
38 import gr.grnet.aquarium.Aquarium
39 import java.io.{FileOutputStream, File}
40 import gr.grnet.aquarium.util.{Loggable, stringOfStackTrace, makeBytes, UTF_8_Charset}
41 import gr.grnet.aquarium.util.date.{TimeHelpers, MutableDateCalc}
42 import gr.grnet.aquarium.event.model.im.IMEventModel
43 import gr.grnet.aquarium.event.model.resource.ResourceEventModel
46 * This is used whenever the property `events.store.folder` is setup in aquarium configuration.
48 * This is mainly a debugging aid. You normally want to disable it in a production environment.
50 * @author Christos KK Loverdos <loverdos@gmail.com>
53 object LocalFSEventStore extends Loggable {
54 private[this] final val NewLine = makeBytes("\n", UTF_8_Charset) // super-fluous!
56 private[this] def writeToFile(file: File,
60 appendString: Option[String] = None): Unit = {
61 val out = new FileOutputStream(file)
63 out.write(makeBytes(dataHeader, UTF_8_Charset))
65 out.write(makeBytes(dataFooter, UTF_8_Charset))
70 out.write(makeBytes(s, UTF_8_Charset))
77 logger.debug("Wrote to file {}", file.getCanonicalPath)
80 private[this] def dateTagForFolder(): String = {
81 new MutableDateCalc(TimeHelpers.nowMillis()).toYYYYMMDD
84 private[this] def createResourceEventsFolder(root: File): File = {
85 val folder0 = new File(root, "rc")
86 val folder = new File(folder0, "rc-%s".format(dateTagForFolder()))
91 private[this] def createIMEventsFolder(root: File): File = {
92 val folder0 = new File(root, "im")
93 val folder = new File(folder0, "im-%s".format(dateTagForFolder()))
98 private[this] def writeJson(tag: String,
100 jsonPayload: Array[Byte],
101 occurredString: String,
102 extraName: Option[String],
104 appendString: Option[String]): Unit = {
107 "%s-%s%s.%s.json".format(
111 case Some(s) ⇒ "-" + s
114 if(isParsed) "p" else "u"
117 val dataHeader = "// %s bytes of payload\n".format(jsonPayload.length)
118 val dataFooter = "\n" + dataHeader
128 def storeUnparsedResourceEvent(aquarium: Aquarium, initialPayload: Array[Byte], exception: Throwable): Unit = {
129 for(root <- aquarium.eventsStoreFolder) {
130 val occurredMDC = new MutableDateCalc(TimeHelpers.nowMillis())
131 val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
132 val rcEventsFolder = createResourceEventsFolder(root)
133 val trace = stringOfStackTrace(exception)
135 writeJson("rc", rcEventsFolder, initialPayload, occurredString, None, false, Some(trace))
139 def storeResourceEvent(aquarium: Aquarium, event: ResourceEventModel, initialPayload: Array[Byte]): Unit = {
140 if(!aquarium.saveResourceEventsToEventsStoreFolder) {
144 require(event ne null, "Resource event must be not null")
146 for(root <- aquarium.eventsStoreFolder) {
147 val occurredMDC = new MutableDateCalc(event.occurredMillis)
148 val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
149 val rcEventsFolder = createResourceEventsFolder(root)
157 Some("[%s]-[%s]-[%s]-[%s]".format(
168 def storeUnparsedIMEvent(aquarium: Aquarium, initialPayload: Array[Byte], exception: Throwable): Unit = {
169 for(root <- aquarium.eventsStoreFolder) {
170 val occurredMDC = new MutableDateCalc(TimeHelpers.nowMillis())
171 val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
172 val imEventsFolder = createIMEventsFolder(root)
173 val trace = stringOfStackTrace(exception)
175 writeJson("im", imEventsFolder, initialPayload, occurredString, None, false, Some(trace))
179 def storeIMEvent(aquarium: Aquarium, event: IMEventModel, initialPayload: Array[Byte]): Unit = {
180 if(!aquarium.saveIMEventsToEventsStoreFolder) {
184 require(event ne null, "IM event must be not null")
186 for(root <- aquarium.eventsStoreFolder) {
187 val occurredMDC = new MutableDateCalc(event.occurredMillis)
188 val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
189 val imEventsFolder = createIMEventsFolder(root)
196 Some("[%s]-[%s]".format(event.id, event.userID)),