001// Copyright (c) FIRST and other WPILib contributors. 002// Open Source Software; you can modify and/or share it under the terms of 003// the WPILib BSD license file in the root directory of this project. 004 005package edu.wpi.first.util.datalog; 006 007/** 008 * A data log. The log file is created immediately upon construction with a temporary filename. The 009 * file may be renamed at any time using the setFilename() function. 010 * 011 * <p>The data log is periodically flushed to disk. It can also be explicitly flushed to disk by 012 * using the flush() function. 013 * 014 * <p>The finish() function is needed only to indicate in the log that a particular entry is no 015 * longer being used (it releases the name to ID mapping). The finish() function is not required to 016 * be called for data to be flushed to disk; entries in the log are written as append() calls are 017 * being made. In fact, finish() does not need to be called at all. 018 * 019 * <p>DataLog calls are thread safe. DataLog uses a typical multiple-supplier, single-consumer 020 * setup. Writes to the log are atomic, but there is no guaranteed order in the log when multiple 021 * threads are writing to it; whichever thread grabs the write mutex first will get written first. 022 * For this reason (as well as the fact that timestamps can be set to arbitrary values), records in 023 * the log are not guaranteed to be sorted by timestamp. 024 */ 025public final class DataLog implements AutoCloseable { 026 /** 027 * Construct a new Data Log. The log will be initially created with a temporary filename. 028 * 029 * @param dir directory to store the log 030 * @param filename filename to use; if none provided, a random filename is generated of the form 031 * "wpilog_{}.wpilog" 032 * @param period time between automatic flushes to disk, in seconds; this is a time/storage 033 * tradeoff 034 * @param extraHeader extra header data 035 */ 036 public DataLog(String dir, String filename, double period, String extraHeader) { 037 m_impl = DataLogJNI.create(dir, filename, period, extraHeader); 038 } 039 040 /** 041 * Construct a new Data Log. The log will be initially created with a temporary filename. 042 * 043 * @param dir directory to store the log 044 * @param filename filename to use; if none provided, a random filename is generated of the form 045 * "wpilog_{}.wpilog" 046 * @param period time between automatic flushes to disk, in seconds; this is a time/storage 047 * tradeoff 048 */ 049 public DataLog(String dir, String filename, double period) { 050 this(dir, filename, period, ""); 051 } 052 053 /** 054 * Construct a new Data Log. The log will be initially created with a temporary filename. 055 * 056 * @param dir directory to store the log 057 * @param filename filename to use; if none provided, a random filename is generated of the form 058 * "wpilog_{}.wpilog" 059 */ 060 public DataLog(String dir, String filename) { 061 this(dir, filename, 0.25); 062 } 063 064 /** 065 * Construct a new Data Log. The log will be initially created with a temporary filename. 066 * 067 * @param dir directory to store the log 068 */ 069 public DataLog(String dir) { 070 this(dir, "", 0.25); 071 } 072 073 /** Construct a new Data Log. The log will be initially created with a temporary filename. */ 074 public DataLog() { 075 this(""); 076 } 077 078 /** 079 * Change log filename. 080 * 081 * @param filename filename 082 */ 083 public void setFilename(String filename) { 084 DataLogJNI.setFilename(m_impl, filename); 085 } 086 087 /** Explicitly flushes the log data to disk. */ 088 public void flush() { 089 DataLogJNI.flush(m_impl); 090 } 091 092 /** 093 * Pauses appending of data records to the log. While paused, no data records are saved (e.g. 094 * AppendX is a no-op). Has no effect on entry starts / finishes / metadata changes. 095 */ 096 public void pause() { 097 DataLogJNI.pause(m_impl); 098 } 099 100 /** Resumes appending of data records to the log. */ 101 public void resume() { 102 DataLogJNI.resume(m_impl); 103 } 104 105 /** 106 * Start an entry. Duplicate names are allowed (with the same type), and result in the same index 107 * being returned (start/finish are reference counted). A duplicate name with a different type 108 * will result in an error message being printed to the console and 0 being returned (which will 109 * be ignored by the append functions). 110 * 111 * @param name Name 112 * @param type Data type 113 * @param metadata Initial metadata (e.g. data properties) 114 * @param timestamp Time stamp (0 to indicate now) 115 * @return Entry index 116 */ 117 public int start(String name, String type, String metadata, long timestamp) { 118 return DataLogJNI.start(m_impl, name, type, metadata, timestamp); 119 } 120 121 /** 122 * Start an entry. Duplicate names are allowed (with the same type), and result in the same index 123 * being returned (start/finish are reference counted). A duplicate name with a different type 124 * will result in an error message being printed to the console and 0 being returned (which will 125 * be ignored by the append functions). 126 * 127 * @param name Name 128 * @param type Data type 129 * @param metadata Initial metadata (e.g. data properties) 130 * @return Entry index 131 */ 132 public int start(String name, String type, String metadata) { 133 return start(name, type, metadata, 0); 134 } 135 136 /** 137 * Start an entry. Duplicate names are allowed (with the same type), and result in the same index 138 * being returned (start/finish are reference counted). A duplicate name with a different type 139 * will result in an error message being printed to the console and 0 being returned (which will 140 * be ignored by the append functions). 141 * 142 * @param name Name 143 * @param type Data type 144 * @return Entry index 145 */ 146 public int start(String name, String type) { 147 return start(name, type, ""); 148 } 149 150 /** 151 * Finish an entry. 152 * 153 * @param entry Entry index 154 * @param timestamp Time stamp (0 to indicate now) 155 */ 156 public void finish(int entry, long timestamp) { 157 DataLogJNI.finish(m_impl, entry, timestamp); 158 } 159 160 /** 161 * Finish an entry. 162 * 163 * @param entry Entry index 164 */ 165 public void finish(int entry) { 166 finish(entry, 0); 167 } 168 169 /** 170 * Updates the metadata for an entry. 171 * 172 * @param entry Entry index 173 * @param metadata New metadata for the entry 174 * @param timestamp Time stamp (0 to indicate now) 175 */ 176 public void setMetadata(int entry, String metadata, long timestamp) { 177 DataLogJNI.setMetadata(m_impl, entry, metadata, timestamp); 178 } 179 180 /** 181 * Updates the metadata for an entry. 182 * 183 * @param entry Entry index 184 * @param metadata New metadata for the entry 185 */ 186 public void setMetadata(int entry, String metadata) { 187 setMetadata(entry, metadata, 0); 188 } 189 190 /** 191 * Appends a record to the log. 192 * 193 * @param entry Entry index, as returned by Start() 194 * @param data Data to record 195 * @param timestamp Time stamp (0 to indicate now) 196 */ 197 public void appendRaw(int entry, byte[] data, long timestamp) { 198 DataLogJNI.appendRaw(m_impl, entry, data, timestamp); 199 } 200 201 @Override 202 public void close() { 203 DataLogJNI.close(m_impl); 204 m_impl = 0; 205 } 206 207 public void appendBoolean(int entry, boolean value, long timestamp) { 208 DataLogJNI.appendBoolean(m_impl, entry, value, timestamp); 209 } 210 211 public void appendInteger(int entry, long value, long timestamp) { 212 DataLogJNI.appendInteger(m_impl, entry, value, timestamp); 213 } 214 215 public void appendFloat(int entry, float value, long timestamp) { 216 DataLogJNI.appendFloat(m_impl, entry, value, timestamp); 217 } 218 219 public void appendDouble(int entry, double value, long timestamp) { 220 DataLogJNI.appendDouble(m_impl, entry, value, timestamp); 221 } 222 223 public void appendString(int entry, String value, long timestamp) { 224 DataLogJNI.appendString(m_impl, entry, value, timestamp); 225 } 226 227 public void appendBooleanArray(int entry, boolean[] arr, long timestamp) { 228 DataLogJNI.appendBooleanArray(m_impl, entry, arr, timestamp); 229 } 230 231 public void appendIntegerArray(int entry, long[] arr, long timestamp) { 232 DataLogJNI.appendIntegerArray(m_impl, entry, arr, timestamp); 233 } 234 235 public void appendFloatArray(int entry, float[] arr, long timestamp) { 236 DataLogJNI.appendFloatArray(m_impl, entry, arr, timestamp); 237 } 238 239 public void appendDoubleArray(int entry, double[] arr, long timestamp) { 240 DataLogJNI.appendDoubleArray(m_impl, entry, arr, timestamp); 241 } 242 243 public void appendStringArray(int entry, String[] arr, long timestamp) { 244 DataLogJNI.appendStringArray(m_impl, entry, arr, timestamp); 245 } 246 247 public long getImpl() { 248 return m_impl; 249 } 250 251 private long m_impl; 252}