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}