লগটিতে কিছু পাঠ্য উপস্থিত থাকলে লগ অনুসরণ এবং একটি আদেশ কার্যকর করার সর্বোত্তম উপায়


54

আমার একটি সার্ভার লগ রয়েছে যা সার্ভারটি শেষ হওয়ার পরে তার লগ ফাইলটিতে পাঠ্যের একটি নির্দিষ্ট লাইন আউটপুট করে। সার্ভারটি শেষ হয়ে গেলে আমি একটি কমান্ড কার্যকর করতে চাই এবং তাই নীচের মতো কিছু করতে চাই:

tail -f /path/to/serverLog | grep "server is up" ...(now, e.g., wget on server)?

এই কাজ করতে সবচেয়ে ভালো উপায় কি?


3
tail -Fলগ রোটেশন পরিচালনা করতে অবশ্যই ভুলবেন না - যেমন my.logপূর্ণ হয়ে যায় এবং এতে চলে আসে my.log.1এবং আপনার প্রক্রিয়াটি একটি নতুন তৈরি করেmy.log
সাগ

উত্তর:


34

একটি সহজ উপায় অদ্ভুত হবে।

tail -f /path/to/serverLog | awk '
                    /Printer is on fire!/ { system("shutdown -h now") }
                    /new USB high speed/  { system("echo \"New USB\" | mail admin") }'

এবং হ্যাঁ, এগুলি উভয়ই কর্নেল লগের আসল বার্তা। পার্ল এটির জন্য ব্যবহার করতে কিছুটা মার্জিত হতে পারে এবং লেজের প্রয়োজনীয়তাও প্রতিস্থাপন করতে পারে। পার্ল ব্যবহার করা হলে এটি এর মতো কিছু দেখবে:

open(my $fd, "<", "/path/to/serverLog") or die "Can't open log";
while(1) {
    if(eof $fd) {
        sleep 1;
        $fd->clearerr;
        next;
    }
    my $line = <$fd>;
    chomp($line);
    if($line =~ /Printer is on fire!/) {
        system("shutdown -h now");
    } elsif($line =~ /new USB high speed/) {
        system("echo \"New USB\" | mail admin");
    }
}

আমি awkএক লাইনে ফ্লাইতে সংক্ষিপ্ত এবং সহজ করার জন্য সমাধানটি পছন্দ করি । তবে, আমি যে কমান্ডটি চালাতে চাইছি তাতে যদি উক্তিগুলি থাকে তবে এটি কিছুটা জটিল হতে পারে, এটির কোনও বিকল্প আছে, সম্ভবত পাইপলাইন এবং যৌগিক কমান্ডগুলি ব্যবহার করে যা সংক্ষিপ্ত ওয়ান-লাইনারের সমাধান দেয় তবে ফলাফলটি কমান্ডটি পাস করার প্রয়োজন হয় না স্ট্রিং হিসাবে?
jonderry

1
@ জোন আপনি স্ক্রিপ্ট হিসাবে awk লিখতে পারেন। স্ক্রিপ্টের প্রথম লাইন হিসাবে "#! / Usr / bin awk -f" ব্যবহার করুন। এটি আমার উদাহরণে বাইরের একক উদ্ধৃতিগুলির প্রয়োজনীয়তা দূর করবে এবং system()কমান্ডের অভ্যন্তরে তাদের ব্যবহারের জন্য মুক্ত করবে ।
পেঙ্গুইন 359

@ পেঙ্গুইন 359, সত্য, তবে কমান্ড লাইন থেকে এটি করা এখনও আকর্ষণীয় হবে। আমার ক্ষেত্রে, আমি যে ভবিষ্যদ্বাণী করতে পারি না এমন অনেকগুলি জিনিস সহ আমি করতে চাই বিভিন্ন রকমের জিনিস রয়েছে, তাই কেবল সার্ভারটি শুরু করতে এবং এটি সমস্ত এক লাইনেই করতে সক্ষম হওয়াই সুবিধাজনক।
jonderry

আমি একটি বিকল্প খুঁজে পেয়েছি, যদিও আমি জানি না এটি কতটা tail -f /path/to/serverLog | grep "server is up" | head -1 && do_some_command
দৃ solid়

@ জোন এটি মাথাটি ব্যবহার করে কিছুটা ভঙ্গুর বলে মনে হচ্ছে। আরও গুরুত্বপূর্ণ, এটি আমার উদাহরণগুলির মতো পুনরাবৃত্তিযোগ্য নয়। যদি "সার্ভারটি আপ" লগের শেষ দশ লাইনে থাকে তবে এটি কমান্ডটি সরিয়ে ফেলবে এবং সঙ্গে সঙ্গে প্রস্থান করবে। আপনি যদি এটি পুনরায় চালু করেন, সম্ভবত এটি অগ্নিকাণ্ড এবং আবার বেরিয়ে আসবে যদি না "লগিনে" সার্ভার থাকা "দশটি লাইন যোগ না করা হয়। যে আরও ভাল কাজ করতে পারে তার একটি পরিবর্তন হল tail -n 0 -f /path/to/serverLog ফাইলের শেষ 0 লাইন পড়বে, তারপরে আরও লাইন মুদ্রণের জন্য অপেক্ষা করবে।
পেঙ্গুইন 359

16

আপনি যদি কেবল একটি সম্ভাবনার সন্ধান করেন এবং ব্যবহার করার চেয়ে awkবা খোলের মধ্যেই বেশিরভাগের মধ্যে থাকতে চান তবে আপনি এর perlমতো কিছু করতে পারেন:

tail -F /path/to/serverLog | 
grep --line-buffered 'server is up' | 
while read ; do my_command ; done

... যা my_commandপ্রতিবার চলবে " সার্ভার শেষ " লগ ফাইলে উপস্থিত হবে। একাধিক সম্ভাবনার জন্য, আপনি সম্ভবত ড্রপ করতে পারেন grepএবং পরিবর্তে এর caseমধ্যে একটি ব্যবহার করতে পারেন while

রাজধানী -Fবলে tailআবর্তিত করা লগ ফাইল জন্য ঘড়ি; উদাহরণস্বরূপ, যদি বর্তমান ফাইলটির নাম পরিবর্তন হয় এবং একই নামের অন্য কোনও ফাইলের স্থান হয়, tailতবে নতুন ফাইলটিতে স্যুইচ হবে।

--line-bufferedবিকল্প বলে grepযে লাইন পর তার বাফার ঘনিষ্ঠরূপে; অন্যথায়, my_commandসময়মতো ফ্যাশনে পৌঁছানো যাবে না (ধরে নেই লগগুলিতে যুক্তিসঙ্গত আকারের লাইন রয়েছে)।


2
আমি এই উত্তরটি সত্যিই পছন্দ করি তবে এটি প্রথমে আমার পক্ষে কার্যকর হয়নি। আমি মনে করি আপনার --line-bufferedবিকল্পটি যুক্ত করতে হবে grep, বা অন্যথায় নিশ্চিত হওয়া উচিত যে এটির আউটপুটটি লাইনের মধ্যে ফ্লাশ করেছে: অন্যথায়, এটি কেবল স্তব্ধ হয়ে যায় এবং my_commandকখনও পৌঁছায় না। আপনি যদি পছন্দ করেন তবে ackএটিতে একটি --flushপতাকা রয়েছে; আপনি যদি পছন্দ করেন তবে agমোড়কের চেষ্টা করুন stdbufstackoverflow.com/questions/28982518/...
doctaphred

আমি চেষ্টা করেছিলাম, ব্যবহার করে do exit ;। দেখে মনে হচ্ছে এটি ঠিক আছে, তবে লেজ কখনই শেষ হয়নি এবং আমাদের স্ক্রিপ্টটি কখনই পরবর্তী লাইনে চলে যায় না। doবিভাগে লেজ বন্ধ করার কোনও উপায় আছে ?
ম্যাক্টিন

14

এই প্রশ্নের উত্তর ইতিমধ্যে দেওয়া হয়েছে বলে মনে হয়, তবে আমি মনে করি এর থেকে আরও ভাল সমাধান আরও আছে।

পরিবর্তে tail | whatever, আমি আপনি সত্যিই কি চান তা মনে করি swatch। সোয়াচ হ'ল এমন একটি প্রোগ্রাম যা আপনি যা চাইছেন তা করার জন্য, লগ ফাইলটি দেখার জন্য এবং লগ লাইনের উপর ভিত্তি করে ক্রিয়াকলাপ সম্পাদনের জন্য ডিজাইন করা। ব্যবহারের জন্য tail|fooপ্রয়োজন হবে যে এটি করার জন্য আপনার একটি টার্মিনাল সক্রিয়ভাবে চলমান। অন্যদিকে সোয়্যাচ একটি ডেমন হিসাবে চালিত হয় এবং সর্বদা আপনার লগগুলি পর্যবেক্ষণ করবে। সমস্ত লিনাক্স ডিস্ট্রোজে সোয়াচ পাওয়া যায়,

আমি আপনাকে এটি চেষ্টা করতে উত্সাহিত করি। আপনি কোনও স্ক্রু ড্রাইভারের পিছনের দিকের সাথে পেরেকটি গুঁজে দিতে পারার অর্থ এই নয় যে আপনার উচিত।

সোয়াচ-এর সেরা ৩০ সেকেন্ডের সেরা টিউটোরিয়ালটি আমি এখানে পেয়েছি: http://www.campin.net/newlogcheck.html


1
এই টিউটোরিয়ালটি এখন 404: /
এরপরে

1
ওয়েবআর্কাইভ আপনার বন্ধু: ওয়েব.আরচিভ.আর.ইউইব
সান

10

আশ্চর্যের বিষয় যে multitailএই ইউটিলিটি সম্পর্কে কেউ উল্লেখ করেনি যার কার্যকারিতা বাইরে রয়েছে। ব্যবহারের একটি উদাহরণ:

পিং-কমান্ডের আউটপুট দেখান এবং এটি যদি একটি সময়সীমা প্রদর্শন করে তবে বর্তমানে লগইন থাকা সমস্ত ব্যবহারকারীকে একটি বার্তা প্রেরণ করুন

multitail -ex timeout "echo timeout | wall" -l "ping 192.168.0.1"

আরও দেখুন অন্য উদাহরণ কয়েক multitailব্যবহার সঞ্চয় করুন।


+1, আমার কোনও ধারণা ছিল না `মাল্টিটাইলে এই ধরণের নিনজা দক্ষতা ছুঁড়ে ফেলা হয়েছিল। যে ইশারা জন্য ধন্যবাদ।
কালেব

8

নিজেই কাজটি করতে পারে

এটি কতটা সহজ এবং পাঠযোগ্য হতে পারে তা দেখুন:

mylog() {
    echo >>/path/to/myscriptLog "$@"
}

while read line;do
    case "$line" in
        *"Printer on fire"* )
            mylog Halting immediately
            shutdown -h now
            ;;
        *DHCPREQUEST* )
            [[ "$line" =~ DHCPREQUEST\ for\ ([^\ ]*)\  ]]
            mylog Incomming or refresh for ${BASH_REMATCH[1]}
            $HOME/SomethingWithNewClient ${BASH_REMATCH[1]}
            ;;
        * )
            mylog "untrapped entry: $line"
            ;;
    esac
  done < <(tail -f /path/to/logfile)

আপনি যখন ব্যাশ ব্যবহার করবেন না regex, এটি খুব দ্রুত থাকতে পারে!

তবে + একটি খুব দক্ষ এবং আকর্ষণীয় টেন্ডেম

তবে উচ্চ লোড সার্ভারের জন্য এবং আমি যেমন পছন্দ করি sedকারণ এটি খুব দ্রুত এবং খুব স্কেলযোগ্য, আমি প্রায়শই এটি ব্যবহার করি:

while read event target lost ; do
    case $event in
        NEW )
            ip2int $target intTarget
            ((count[intTarget]++))
        ...

    esac
done < <(tail -f /path/logfile | sed -une '
  s/^.*New incom.*from ip \([0-9.]\+\) .*$/NEW \1/p;
  s/^.*Auth.*ip \([0-9.]\+\) failed./FAIL \1/p;
  ...
')

6

এইভাবেই আমি এটি করা শুরু করেছিলাম তবে এটির সাথে আরও পরিশীলিত হয়ে উঠেছে। কয়েকটি বিষয় সম্পর্কে উদ্বিগ্ন:

  1. লগের লেজটিতে ইতিমধ্যে "সার্ভার আপ" রয়েছে।
  2. লেজ প্রক্রিয়াটি এটি একবার খুঁজে পাওয়ার পরে স্বয়ংক্রিয়ভাবে শেষ হচ্ছে।

আমি এর লাইনে কিছু ব্যবহার করি:

RELEASE=/tmp/${RANDOM}$$
(
  trap 'false' 1
  trap "rm -f ${RELEASE}" 0
  while ! [ -s ${RELEASE} ]; do sleep 3; done
  # You can put code here if you want to do something
  # once the grep succeeds.
) & wait_pid=$!
tail --pid=${wait_pid} -F /path/to/serverLog \
| sed "1,10d" \
| grep "server is up" > ${RELEASE}

ফাইলটিতে ডেটা tailনা হওয়া পর্যন্ত এটি খোলার মাধ্যমে কাজ করে ${RELEASE}

একবার এটি grepসফল হয়:

  1. ${RELEASE}যা ইচ্ছা আউটপুট লিখেছেন
  2. বিনষ্ট ${wait_pid}প্রক্রিয়া
  3. প্রস্থান করুন tail

দ্রষ্টব্য: শুরুতে উত্পাদিত sedলাইনের সংখ্যা নির্ধারণের জন্য এটি আরও পরিশীলিত হতে পারে tailএবং সেই সংখ্যাটি সরান। তবে সাধারণত, এটি 10।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.