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 gr.grnet.aquarium.message.avro.gen.{IMEventMsg, ResourceEventMsg}
40 import gr.grnet.aquarium.util.date.{TimeHelpers, MutableDateCalc}
41 import gr.grnet.aquarium.util.{Loggable, stringOfStackTrace, makeBytes, UTF_8_Charset}
42 import java.io.{FileOutputStream, File}
45 * This is used whenever the property `events.store.folder` is setup in aquarium configuration.
47 * This is mainly a debugging aid. You normally want to disable it in a production environment.
49 * @author Christos KK Loverdos <loverdos@gmail.com>
52 object LocalFSEventStore extends Loggable {
53 private[this] final val NewLine = makeBytes("\n", UTF_8_Charset) // super-fluous!
55 private[this] def writeToFile(
60 appendString: Option[String] = None
63 val out = new FileOutputStream(file)
65 out.write(makeBytes(dataHeader, UTF_8_Charset))
67 out.write(makeBytes(dataFooter, UTF_8_Charset))
72 out.write(makeBytes(s, UTF_8_Charset))
79 logger.debug("Wrote to file {}", file.getCanonicalPath)
82 private[this] def dateTagForFolder(): String = {
83 new MutableDateCalc(TimeHelpers.nowMillis()).toYYYYMMDD
86 private[this] def createResourceEventsFolder(root: File): File = {
87 val folder0 = new File(root, "rc")
88 val folder = new File(folder0, "rc-%s".format(dateTagForFolder()))
93 private[this] def createIMEventsFolder(root: File): File = {
94 val folder0 = new File(root, "im")
95 val folder = new File(folder0, "im-%s".format(dateTagForFolder()))
100 private[this] def writeJson(
103 jsonPayload: Array[Byte],
104 occurredString: String,
105 extraName: Option[String],
107 appendString: Option[String]
112 "%s-%s%s.%s.json".format(
116 case Some(s) ⇒ "-" + s
119 if(isParsed) "p" else "u"
122 val dataHeader = "// %s bytes of payload\n".format(jsonPayload.length)
123 val dataFooter = "\n" + dataHeader
133 def storeUnparsedResourceEvent(aquarium: Aquarium, initialPayload: Array[Byte], exception: Throwable): Unit = {
134 for(root <- aquarium.eventsStoreFolder) {
135 val occurredMDC = new MutableDateCalc(TimeHelpers.nowMillis())
136 val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
137 val rcEventsFolder = createResourceEventsFolder(root)
138 val trace = stringOfStackTrace(exception)
140 writeJson("rc", rcEventsFolder, initialPayload, occurredString, None, false, Some(trace))
144 def storeResourceEvent(aquarium: Aquarium, event: ResourceEventMsg, initialPayload: Array[Byte]): Unit = {
145 if(!aquarium.saveResourceEventsToEventsStoreFolder) {
149 require(event ne null, "Resource event must be not null")
151 for(root <- aquarium.eventsStoreFolder) {
152 val occurredMDC = new MutableDateCalc(event.getOccurredMillis)
153 val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
154 val rcEventsFolder = createResourceEventsFolder(root)
162 Some("[%s]-[%s]-[%s]-[%s]".format(
166 event.getInstanceID)),
173 def storeUnparsedIMEvent(aquarium: Aquarium, initialPayload: Array[Byte], exception: Throwable): Unit = {
174 for(root <- aquarium.eventsStoreFolder) {
175 val occurredMDC = new MutableDateCalc(TimeHelpers.nowMillis())
176 val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
177 val imEventsFolder = createIMEventsFolder(root)
178 val trace = stringOfStackTrace(exception)
180 writeJson("im", imEventsFolder, initialPayload, occurredString, None, false, Some(trace))
184 def storeIMEvent(aquarium: Aquarium, event: IMEventMsg, initialPayload: Array[Byte]): Unit = {
185 if(!aquarium.saveIMEventsToEventsStoreFolder) {
189 require(event ne null, "IM event must be not null")
191 for(root <- aquarium.eventsStoreFolder) {
192 val occurredMDC = new MutableDateCalc(event.getOccurredMillis)
193 val occurredString = occurredMDC.toFilename_YYYYMMDDHHMMSSSSS
194 val imEventsFolder = createIMEventsFolder(root)
201 Some("[%s]-[%s]".format(event.getOriginalID, event.getUserID)),