diff --git a/smartmontools/CHANGELOG b/smartmontools/CHANGELOG
index 4e77d866a4904fe3cd984c8b973c32e68cbc6286..475cf28aea4577c95f6e6ef76b6d3ea9788be501 100644
--- a/smartmontools/CHANGELOG
+++ b/smartmontools/CHANGELOG
@@ -42,6 +42,12 @@ NOTES FOR FUTURE RELEASES: see TODO file.
 
 <DEVELOPERS: ADDITIONS TO THE CHANGE LOG GO JUST BELOW HERE, PLEASE>
 
+  [MS] Add experimental feature to log attribute values at each check 
+       cycle (ATA only), activated with the smartd option 
+       "-A PREFIX" / "--attributelog=PREFIX".
+       Introduce configure options "--enable-attributelog" and
+       "--with-attributelog=PREFIX" to enable feature by default.
+
   [DG] [SAT] Heads up about a non backwardly compatible change
        introduced in draft SAT-2 (sat2r8b.pdf) that will break our
        existing SAT processing code. Action needed if change stands.
diff --git a/smartmontools/Makefile.am b/smartmontools/Makefile.am
index ab5a199f0473c60af7f438a6d3ce9355cbe3131a..3b4f484088646b493f1fdb354f2c53b190f4fcb8 100644
--- a/smartmontools/Makefile.am
+++ b/smartmontools/Makefile.am
@@ -18,6 +18,9 @@ endif
 if ENABLE_SAVESTATES
 AM_CPPFLAGS += -DSMARTMONTOOLS_SAVESTATES='"$(savestates)"'
 endif
+if ENABLE_ATTRIBUTELOG
+AM_CPPFLAGS += -DSMARTMONTOOLS_ATTRIBUTELOG='"$(attributelog)"'
+endif
 
 sbin_PROGRAMS = smartd 	\
 		smartctl
@@ -312,6 +315,11 @@ if ENABLE_SAVESTATES
 savestates_DATA =
 endif
 
+if ENABLE_ATTRIBUTELOG
+# Create $(attributelogdir) only
+attributelog_DATA =
+endif
+
 smartd.conf.5.in: smartd.8.in
 	sed '1,/STARTINCLUDE/ D;/ENDINCLUDE/,$$D' < $(srcdir)/smartd.8.in > $(top_builddir)/tmp.directives
 	sed '/STARTINCLUDE/,$$D'  < $(srcdir)/smartd.conf.5.in > $(top_builddir)/tmp.head
@@ -413,6 +421,12 @@ else
 MAN_SAVESTATES = sed '/BEGIN ENABLE_SAVESTATES/,/END ENABLE_SAVESTATES/d'
 endif
 
+if ENABLE_ATTRIBUTELOG
+MAN_ATTRIBUTELOG = sed "s|/usr/local/var/lib/smartmontools/attrlog\\.|$(attributelog)|g"
+else
+MAN_ATTRIBUTELOG = sed '/BEGIN ENABLE_ATTRIBUTELOG/,/END ENABLE_ATTRIBUTELOG/d'
+endif
+
 if OS_FREEBSD
 .for file in $(man_MANS)
 ${file}: $(srcdir)/${file}.in Makefile svnversion.h
@@ -426,7 +440,8 @@ ${file}: $(srcdir)/${file}.in Makefile svnversion.h
 	     s|/usr/local/etc/smartd\\.conf|$(sysconfdir)/smartd.conf|g; \
 	     s|/usr/local/etc/smart_drivedb\\.h|$(sysconfdir)/smart_drivedb\\.h|g" ${.ALLSRC:M*.in} | \
 	$(MAN_DRIVEDB) | \
-	$(MAN_SAVESTATES) > $@
+	$(MAN_SAVESTATES) | \
+	$(MAN_ATTRIBUTELOG) > $@
 .endfor
 else
 smart%: $(srcdir)/smart%.in Makefile svnversion.h
@@ -440,7 +455,8 @@ smart%: $(srcdir)/smart%.in Makefile svnversion.h
 	sed "s|/usr/local/etc/smartd\\.conf|$(sysconfdir)/smartd.conf|g" | \
 	sed "s|/usr/local/etc/smart_drivedb\\.h|$(sysconfdir)/smart_drivedb\\.h|g" | \
 	$(MAN_DRIVEDB) | \
-	$(MAN_SAVESTATES) > $@
+	$(MAN_SAVESTATES) | \
+	$(MAN_ATTRIBUTELOG) > $@
 endif
 
 # Commands to convert man pages into .html and .txt
diff --git a/smartmontools/configure.in b/smartmontools/configure.in
index 1c4377325c28dfb1510c381e81e8ed880cd0b2fe..a3f5ee1d98d9d0ee724a749c200220b30e5e5284 100644
--- a/smartmontools/configure.in
+++ b/smartmontools/configure.in
@@ -169,6 +169,16 @@ AC_SUBST(savestates)
 AC_SUBST(savestatesdir)
 AM_CONDITIONAL(ENABLE_SAVESTATES, [test "$enable_savestates" = "yes"])
 
+AC_ARG_ENABLE(attributelog, [AC_HELP_STRING([--enable-attributelog],[Enables default smartd attribute log files])])
+
+AC_ARG_WITH(attributelog,
+  [AC_HELP_STRING([--with-attributelog=PREFIX],[Prefix for default smartd attribute log files (implies --enable-attributelog) [LOCALSTATEDIR/lib/smartmontools/attrlog.]])],
+  [attributelog="$withval"; enable_attributelog="yes"],
+  [attributelog=; test "$enable_attributelog" = "yes" && attributelog='${localstatedir}/lib/${PACKAGE}/attrlog.'])
+attributelogdir="${attributelog%/*}"
+AC_SUBST(attributelog)
+AC_SUBST(attributelogdir)
+AM_CONDITIONAL(ENABLE_ATTRIBUTELOG, [test "$enable_attributelog" = "yes"])
 
 AC_ARG_ENABLE(sample,[AC_HELP_STRING([--enable-sample],[Enables appending .sample to the installed smartd rc script and configuration file])],[smartd_suffix='.sample'],[smartd_suffix=''])
 AC_SUBST(smartd_suffix)
diff --git a/smartmontools/smartd.8.in b/smartmontools/smartd.8.in
index 4bc1eaa305a8e8115844ac7ce3379df0652dfe40..b1eff75b36eb61a080e931f068311924cc70580d 100644
--- a/smartmontools/smartd.8.in
+++ b/smartmontools/smartd.8.in
@@ -128,6 +128,31 @@ below).
 OPTIONS
 Long options are not supported on all systems.  Use \fB\'smartd
 \-h\'\fP to see the available options.
+
+.TP
+.B \-A PREFIX, \-\-attributelog=PREFIX
+[NEW EXPERIMENTAL SMARTD FEATURE] [ATA ONLY]
+Writes \fBsmartd\fP attribute information (normalized and raw attribute values)
+to files \'PREFIX\'\'MODEL\-SERIAL.ata.csv\'. At each check cycle attributes
+are logged as a line of semicolon separated triplets of the form
+"attribute-ID;attribute-norm-value;attribute-raw-value;". Each line is
+led by a date string of the form "yyyy-mm-dd HH:MM:SS" (in UTC).
+
+.\" BEGIN ENABLE_ATTRIBUTELOG
+If this option is not specified, attribute information is written to files
+\'/usr/local/var/lib/smartmontools/attrlog.MODEL\-SERIAL.ata.csv\'.
+To disable attribute log files, specify this option with an empty string
+argument: \'-A ""\'.
+.\" END ENABLE_ATTRIBUTELOG
+MODEL and SERIAL are build from drive identify information, invalid
+characters are replaced by underline.
+
+If the PREFIX has the form \'/path/dir/\' (e.g. \'/var/lib/smartd/\'), then
+files \'MODEL\-SERIAL.ata.csv\' are created in directory \'/path/dir\'.
+If the PREFIX has the form \'/path/name\' (e.g. \'/var/lib/misc/attrlog\-\'),
+then files 'nameMODEL\-SERIAL.ata.csv' are created in directory '/path/'.
+The path must be absolute, except if debug mode is enabled.
+
 .TP
 .B \-B [+]FILE, \-\-drivedb=[+]FILE
 [NEW EXPERIMENTAL SMARTD FEATURE] Read the drive database from FILE.
diff --git a/smartmontools/smartd.cpp b/smartmontools/smartd.cpp
index cc4792ce6600e063f79b5f537253857ad1f3300d..00737f7b0a60647b32ca945154e652064adf3db6 100644
--- a/smartmontools/smartd.cpp
+++ b/smartmontools/smartd.cpp
@@ -159,6 +159,13 @@ static std::string state_path_prefix
 #endif
                                     ;
 
+// command-line: path prefix of attribute log file, empty if no logs.
+static std::string attrlog_path_prefix
+#ifdef SMARTMONTOOLS_ATTRIBUTELOG
+          = SMARTMONTOOLS_ATTRIBUTELOG
+#endif
+                                    ;
+
 // configuration file name
 #define CONFIGFILENAME "smartd.conf"
 
@@ -241,6 +248,7 @@ struct dev_config
   std::string name;                       // Device name
   std::string dev_type;                   // Device type argument from -d directive, empty if none
   std::string state_file;                 // Path of the persistent state file, empty if none
+  std::string attrlog_file;               // Path of the persistent attrlog file, empty if none
   bool smartcheck;                        // Check SMART status
   bool usagefailed;                       // Check for failed Usage Attributes
   bool prefail;                           // Track changes in Prefail Attributes
@@ -653,6 +661,32 @@ static bool write_dev_state(const char * path, const persistent_dev_state & stat
   return true;
 }
 
+// Write to the attrlog file
+static bool write_dev_attrlog(const char * path, const persistent_dev_state & state)
+{
+  stdio_file f(path, "a");
+  if (!f) {
+    pout("Cannot create attribute log file \"%s\"\n", path);
+    return false;
+  }
+
+  // ATA ONLY
+  time_t now = time(0);
+  struct tm * tms = gmtime(&now);
+  fprintf(f, "%d-%02d-%02d %02d:%02d:%02d;",
+             1900+tms->tm_year, 1+tms->tm_mon, tms->tm_mday,
+             tms->tm_hour, tms->tm_min, tms->tm_sec);
+  for (int i = 0; i < NUMBER_ATA_SMART_ATTRIBUTES; i++) {
+    const persistent_dev_state::ata_attribute & pa = state.ata_attributes[i];
+    if (!pa.id)
+      continue;
+    fprintf(f, "\t%d;%d;%"PRIu64";", pa.id, pa.val, pa.raw);
+  }
+  fprintf(f, "\n");
+
+  return true;
+}
+
 // Write all state files. If write_always is false, don't write
 // unless must_write is set.
 static void write_all_dev_states(const dev_config_vector & configs,
@@ -675,6 +709,19 @@ static void write_all_dev_states(const dev_config_vector & configs,
   }
 }
 
+// Write to all attrlog files
+static void write_all_dev_attrlogs(const dev_config_vector & configs,
+                                   dev_state_vector & states)
+{
+  for (unsigned i = 0; i < states.size(); i++) {
+    const dev_config & cfg = configs.at(i);
+    if (cfg.attrlog_file.empty())
+      continue;
+    dev_state & state = states[i];
+    write_dev_attrlog(cfg.attrlog_file.c_str(), state);
+  }
+}
+
 // remove the PID file
 void RemovePidFile(){
   if (!pid_file.empty()) {
@@ -1769,21 +1816,24 @@ static int ATADeviceScan(dev_config & cfg, dev_state & state, ata_device * atade
   // close file descriptor
   CloseDevice(atadev, name);
 
-  if (!state_path_prefix.empty()) {
+  if (!state_path_prefix.empty() || !attrlog_path_prefix.empty()) {
     // Build file name for state file
     char model[40+1], serial[20+1];
     format_ata_string(model, drive.model, sizeof(model)-1, fix_swapped_id);
     format_ata_string(serial, drive.serial_no, sizeof(serial)-1, fix_swapped_id);
     std::replace_if(model, model+strlen(model), not_allowed_in_filename, '_');
     std::replace_if(serial, serial+strlen(serial), not_allowed_in_filename, '_');
-    cfg.state_file = strprintf("%s%s-%s.ata.state", state_path_prefix.c_str(), model, serial);
-
-    // Read previous state
-    if (read_dev_state(cfg.state_file.c_str(), state)) {
-      PrintOut(LOG_INFO, "Device: %s, state read from %s\n", name, cfg.state_file.c_str());
-      // Copy ATA attribute values to temp state
-      state.update_temp_state();
+    if (!state_path_prefix.empty()) {
+      cfg.state_file = strprintf("%s%s-%s.ata.state", state_path_prefix.c_str(), model, serial);
+      // Read previous state
+      if (read_dev_state(cfg.state_file.c_str(), state)) {
+        PrintOut(LOG_INFO, "Device: %s, state read from %s\n", name, cfg.state_file.c_str());
+        // Copy ATA attribute values to temp state
+        state.update_temp_state();
+      }
     }
+    if (!attrlog_path_prefix.empty())
+      cfg.attrlog_file = strprintf("%s%s-%s.ata.csv", attrlog_path_prefix.c_str(), model, serial);
   }
 
   // Start self-test regex check now if time was not read from state file
@@ -1926,6 +1976,10 @@ static int SCSIDeviceScan(dev_config & cfg, dev_state & state, scsi_device * scs
   if (!state_path_prefix.empty()) {
     PrintOut(LOG_INFO, "Device: %s, persistence not yet supported for SCSI; ignoring -s option.\n", device);
   }
+  // TODO: Build file name for attribute log file
+  if (!attrlog_path_prefix.empty()) {
+    PrintOut(LOG_INFO, "Device: %s, attribute log not yet supported for SCSI; ignoring -A option.\n", device);
+  }
 
   // close file descriptor
   CloseDevice(scsidev, device);
@@ -3677,7 +3731,7 @@ void ParseOpts(int argc, char **argv){
   char *tailptr;
   long lchecktime;
   // Please update GetValidArgList() if you edit shortopts
-  const char *shortopts = "c:l:q:dDni:p:r:s:B:Vh?";
+  const char *shortopts = "c:l:q:dDni:p:r:s:A:B:Vh?";
   char *arg;
   // Please update GetValidArgList() if you edit longopts
   struct option longopts[] = {
@@ -3693,6 +3747,7 @@ void ParseOpts(int argc, char **argv){
     { "pidfile",        required_argument, 0, 'p' },
     { "report",         required_argument, 0, 'r' },
     { "savestates",     required_argument, 0, 's' },
+    { "attributelog",   required_argument, 0, 'A' },
     { "drivedb",        required_argument, 0, 'B' },
 #if defined(_WIN32) || defined(__CYGWIN__)
     { "service",        no_argument,       0, 'n' },
@@ -3837,6 +3892,10 @@ void ParseOpts(int argc, char **argv){
       // path prefix of persistent state file
       state_path_prefix = optarg;
       break;
+    case 'A':
+      // path prefix of attribute log file
+      attrlog_path_prefix = optarg;
+      break;
     case 'B':
       {
         const char * path = optarg;
@@ -3939,6 +3998,16 @@ void ParseOpts(int argc, char **argv){
     EXIT(EXIT_BADCMD);
   }
 
+  // absolute path is required due to chdir('/') after fork().
+  if (!attrlog_path_prefix.empty() && !debugmode && !is_abs_path(attrlog_path_prefix.c_str())) {
+    debugmode=1;
+    PrintHead();
+    PrintOut(LOG_CRIT, "=======> INVALID CHOICE OF OPTIONS: -s <======= \n\n");
+    PrintOut(LOG_CRIT, "Error: relative path %s is only allowed in debug (-d) mode\n\n",
+      attrlog_path_prefix.c_str());
+    EXIT(EXIT_BADCMD);
+  }
+
   // Read or init drive database
   if (!no_defaultdb) {
     unsigned char savedebug = debugmode; debugmode = 1;
@@ -4301,6 +4370,10 @@ int main_worker(int argc, char **argv)
       write_all_dev_states(configs, states, write_states_always);
     write_states_always = false;
 
+    // Write attribute logs
+    if (!attrlog_path_prefix.empty())
+      write_all_dev_attrlogs(configs, states);
+
     // user has asked us to exit after first check
     if (quit==3) {
       PrintOut(LOG_INFO,"Started with '-q onecheck' option. All devices sucessfully checked once.\n"